Merge lp:~glmark2-dev/glmark2/canvas-drm-rebranch into lp:glmark2/2011.11

Proposed by Jesse Barker
Status: Merged
Merged at revision: 257
Proposed branch: lp:~glmark2-dev/glmark2/canvas-drm-rebranch
Merge into: lp:glmark2/2011.11
Diff against target: 907 lines (+798/-12)
6 files modified
INSTALL (+1/-1)
src/canvas-drm.cpp (+587/-0)
src/canvas-drm.h (+132/-0)
src/main.cpp (+6/-2)
src/wscript_build (+43/-0)
wscript (+29/-9)
To merge this branch: bzr merge lp:~glmark2-dev/glmark2/canvas-drm-rebranch
Reviewer Review Type Date Requested Status
Alexandros Frantzis Approve
Jesse Barker Needs Resubmitting
Review via email: mp+138605@code.launchpad.net

Description of the change

CanvasDRM: Add a new canvas type that renders directly to DRM-managed buffers rather than going through X11. The canvas uses GBM for surface management, DRM (KMS) for mode control and page flip, and EGL for rendering context and config management. Client API support is predicated upon the EGL, but both OpenGL and OpenGL ES 2.0 are supported.

This work was originally done on lp:~glmark2-dev/glmark2/canvas-drm, however, based upon review comments there, it was decided it would be cleaner (with respect to other development branches that have been merged in the interim) to rebranch and reintegrate the work. So, I rebranched from current trunk and then did a 'bzr merge --interactive' from canvas-drm into this branch and de-selected the changes relating to egl-state.{h,cpp}. I think we lose a bit of the revision history, but actually gain a bit of clarity.

To post a comment you must log in.
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Rendering works fine on the platforms I have tested. The only problems I see are during shutdown:

1. Pressing Ctrl+C occasionally doesn't seem to reset the crtc correctly, so I end up with a blank screen. It also always causes an error message to be displayed (Error in select: -1).

2. Pressing Enter (and therefore flushing stdin), causes a segfault. This happens because we are leaving DRMState::do_flip() with both surface buffers locked. Next time we call gbm_surface_lock_front_buffer(surface_) we get back a NULL value which we currently don't handle properly (i.e. we just use it). We get into the same situation if select fails etc

(1) is not critical, so I am ok with shipping this as part of an experimental drm backend release (perhaps we could add a warning about the experimental status when startinp up?).

On the other hand, I think (2) should be fixed before this release, if possible, as it's relatively easy for a user to cause a segfault. For example, a user that wants to quit will probably try pressing ESC (which won't work), then some keys then Enter.

review: Needs Fixing
Revision history for this message
Jesse Barker (jesse-barker) wrote :

> Rendering works fine on the platforms I have tested. The only problems I see
> are during shutdown:
>
> 1. Pressing Ctrl+C occasionally doesn't seem to reset the crtc correctly, so I
> end up with a blank screen. It also always causes an error message to be
> displayed (Error in select: -1).

This obviously works better for you than it does for me (possibly a driver-specific thing?).

>
> 2. Pressing Enter (and therefore flushing stdin), causes a segfault. This
> happens because we are leaving DRMState::do_flip() with both surface buffers
> locked. Next time we call gbm_surface_lock_front_buffer(surface_) we get back
> a NULL value which we currently don't handle properly (i.e. we just use it).
> We get into the same situation if select fails etc

Are you saying that there's a segfault when you press <enter> after glmark2 exits normally? I'm not clear I've ever see this, but I think I'm misunderstanding the scenario.

>
> (1) is not critical, so I am ok with shipping this as part of an experimental
> drm backend release (perhaps we could add a warning about the experimental
> status when startinp up?).

Probably should declare this a bit experimental in any case.

>
> On the other hand, I think (2) should be fixed before this release, if
> possible, as it's relatively easy for a user to cause a segfault. For example,
> a user that wants to quit will probably try pressing ESC (which won't work),
> then some keys then Enter.

Agreed. I'll try to reproduce. If you can provide more info on how to reproduce, that would be very useful.

cheers,
Jesse

256. By Jesse Barker

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.

Revision history for this message
Jesse Barker (jesse-barker) wrote :

OK, got it. I reproduced the behavior, and have pushed a fix at revision 256. This works fine for me from both a serial console, as well as the "main" console (Ctrl-Alt-F1). The signal handler is now better encapsulated within DRMState, and allows the resources to be released properly. I've squelched the "error in select" message by making it debug only, as the vast majority of the time we would see that is precisely the case where a user interrupt has broken us out. I also added a notice to CanvasDRM::init() to indicate that the DRM canvas is experimental and is subject to change with the evolution of buffer management and modesetting APIs.

review: Needs Resubmitting
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Even with the latest changes, I still get stuck with the glmark2 buffer on screen occasionally (~1 out of 5 times) after exiting with Ctrl-C. There are no errors or hangs, and if I switch to the X11 VT and back again, everything is displayed correctly.

> Are you saying that there's a segfault when you press <enter> after glmark2 exits normally?
> I'm not clear I've ever see this, but I think I'm misunderstanding the scenario.

To reproduce, start glmark2*-drm and press enter while a benchmark is running.

Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

> Even with the latest changes, I still get stuck with the glmark2 buffer on
> screen occasionally (~1 out of 5 times) after exiting with Ctrl-C. There are
> no errors or hangs, and if I switch to the X11 VT and back again, everything
> is displayed correctly.

Note that this happens for me only with radeon; I can't reproduce it at all with i915 (tried until my fingers got tired of pressing Ctrl-C ;)). This could well by some kind of driver issue, so I don't think it's worth pursuing further for now.

> > Are you saying that there's a segfault when you press <enter> after glmark2
> exits normally?
> > I'm not clear I've ever see this, but I think I'm misunderstanding the
> scenario.
>
> To reproduce, start glmark2*-drm and press enter while a benchmark is running.

This issue, however, is 100% reproducible on both platforms.

257. By Jesse Barker

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.

Revision history for this message
Jesse Barker (jesse-barker) wrote :

Got rid of the need (well, the need already wasn't there ;-) for listening on stdin for arbitrary user input. We also didn't need to watch for a time out. Things work fine for me, even with interspersed <Enter> and <Ctrl-C> presses.

review: Needs Resubmitting
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'INSTALL'
2--- INSTALL 2011-01-25 15:07:17 +0000
3+++ INSTALL 2012-12-17 22:54:19 +0000
4@@ -2,7 +2,7 @@
5
6 To configure glmark2 use:
7
8-$ ./waf configure [--enable-gl --enable-glesv2 --data-path=DATA_PATH --prefix=PREFIX]
9+$ ./waf configure [--enable-gl --enable-glesv2 --enable-gl-drm --enable-glesv2-drm --data-path=DATA_PATH --prefix=PREFIX]
10
11 To build use:
12
13
14=== added file 'src/canvas-drm.cpp'
15--- src/canvas-drm.cpp 1970-01-01 00:00:00 +0000
16+++ src/canvas-drm.cpp 2012-12-17 22:54:19 +0000
17@@ -0,0 +1,587 @@
18+//
19+// Copyright © 2012 Linaro Limited
20+//
21+// This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
22+//
23+// glmark2 is free software: you can redistribute it and/or modify it under the
24+// terms of the GNU General Public License as published by the Free Software
25+// Foundation, either version 3 of the License, or (at your option) any later
26+// version.
27+//
28+// glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
29+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
30+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
31+// details.
32+//
33+// You should have received a copy of the GNU General Public License along with
34+// glmark2. If not, see <http://www.gnu.org/licenses/>.
35+//
36+// Authors:
37+// Simon Que
38+// Jesse Barker
39+//
40+#include "canvas-drm.h"
41+#include "log.h"
42+#include "options.h"
43+#include "util.h"
44+
45+#include <fcntl.h>
46+#include <poll.h>
47+#include <signal.h>
48+#include <string.h>
49+#include <time.h>
50+
51+#include <fstream>
52+#include <sstream>
53+#include <list>
54+
55+/******************
56+ * Public methods *
57+ ******************/
58+
59+bool
60+CanvasDRM::reset()
61+{
62+ if (!reset_context())
63+ return false;
64+
65+ if (!make_current())
66+ return false;
67+
68+ if (!supports_gl2()) {
69+ Log::error("Glmark2 needs OpenGL(ES) version >= 2.0 to run"
70+ " (but version string is: '%s')!\n",
71+ glGetString(GL_VERSION));
72+ return false;
73+ }
74+
75+ glViewport(0, 0, width_, height_);
76+ glEnable(GL_DEPTH_TEST);
77+ glDepthFunc(GL_LEQUAL);
78+ glEnable(GL_CULL_FACE);
79+ glCullFace(GL_BACK);
80+
81+ clear();
82+ egl_.swap();
83+
84+ if (!drm_.reset()) {
85+ return false;
86+ }
87+
88+ return true;
89+}
90+
91+void
92+DRMState::fb_destroy_callback(gbm_bo* bo, void* data)
93+{
94+ DRMFBState* fb = reinterpret_cast<DRMFBState*>(data);
95+ if (fb && fb->fb_id) {
96+ drmModeRmFB(fb->fd, fb->fb_id);
97+ }
98+ delete fb;
99+ gbm_device* dev = gbm_bo_get_device(bo);
100+ Log::debug("Got GBM device handle %p from buffer object\n", dev);
101+}
102+
103+DRMFBState*
104+DRMState::fb_get_from_bo(gbm_bo* bo)
105+{
106+ DRMFBState* fb = reinterpret_cast<DRMFBState*>(gbm_bo_get_user_data(bo));
107+ if (fb) {
108+ return fb;
109+ }
110+
111+ unsigned int width = gbm_bo_get_width(bo);
112+ unsigned int height = gbm_bo_get_height(bo);
113+ unsigned int stride = gbm_bo_get_stride(bo);
114+ unsigned int handle = gbm_bo_get_handle(bo).u32;
115+ unsigned int fb_id(0);
116+ int status = drmModeAddFB(fd_, width, height, 24, 32, stride, handle, &fb_id);
117+ if (status < 0) {
118+ Log::error("Failed to create FB: %d\n", status);
119+ return 0;
120+ }
121+
122+ fb = new DRMFBState();
123+ fb->fd = fd_;
124+ fb->bo = bo;
125+ fb->fb_id = fb_id;
126+
127+ gbm_bo_set_user_data(bo, fb, fb_destroy_callback);
128+ return fb;
129+}
130+
131+bool
132+DRMState::init_gbm()
133+{
134+ dev_ = gbm_create_device(fd_);
135+ if (!dev_) {
136+ Log::error("Failed to create GBM device\n");
137+ return false;
138+ }
139+
140+ surface_ = gbm_surface_create(dev_, mode_->hdisplay, mode_->vdisplay,
141+ GBM_FORMAT_XRGB8888,
142+ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
143+ if (!surface_) {
144+ Log::error("Failed to create GBM surface\n");
145+ return false;
146+ }
147+
148+ return true;
149+}
150+
151+bool
152+DRMState::init()
153+{
154+ // TODO: Replace this with something that explicitly probes for the loaded
155+ // driver (udev?).
156+ static const char* drm_modules[] = {
157+ "i915",
158+ "nouveau",
159+ "radeon",
160+ "vmgfx",
161+ "omapdrm",
162+ "exynos"
163+ };
164+
165+ unsigned int num_modules(sizeof(drm_modules)/sizeof(drm_modules[0]));
166+ for (unsigned int m = 0; m < num_modules; m++) {
167+ fd_ = drmOpen(drm_modules[m], 0);
168+ if (fd_ < 0) {
169+ Log::debug("Failed to open DRM module '%s'\n", drm_modules[m]);
170+ continue;
171+ }
172+ Log::debug("Opened DRM module '%s'\n", drm_modules[m]);
173+ break;
174+ }
175+
176+ if (fd_ < 0) {
177+ Log::error("Failed to find a suitable DRM device\n");
178+ return false;
179+ }
180+
181+ resources_ = drmModeGetResources(fd_);
182+ if (!resources_) {
183+ Log::error("drmModeGetResources failed\n");
184+ return false;
185+ }
186+
187+ // Find a connected connector
188+ for (int c = 0; c < resources_->count_connectors; c++) {
189+ connector_ = drmModeGetConnector(fd_, resources_->connectors[c]);
190+ if (DRM_MODE_CONNECTED == connector_->connection) {
191+ break;
192+ }
193+ drmModeFreeConnector(connector_);
194+ connector_ = 0;
195+ }
196+
197+ if (!connector_) {
198+ Log::error("Failed to find a suitable connector\n");
199+ return false;
200+ }
201+
202+ // Find the best resolution (we will always operate full-screen).
203+ unsigned int bestArea(0);
204+ for (int m = 0; m < connector_->count_modes; m++) {
205+ drmModeModeInfo* curMode = &connector_->modes[m];
206+ unsigned int curArea = curMode->hdisplay * curMode->vdisplay;
207+ if (curArea > bestArea) {
208+ mode_ = curMode;
209+ bestArea = curArea;
210+ }
211+ }
212+
213+ if (!mode_) {
214+ Log::error("Failed to find a suitable mode\n");
215+ return false;
216+ }
217+
218+ // Find a suitable encoder
219+ for (int e = 0; e < resources_->count_encoders; e++) {
220+ encoder_ = drmModeGetEncoder(fd_, resources_->encoders[e]);
221+ if (encoder_ && encoder_->encoder_id == connector_->encoder_id) {
222+ break;
223+ }
224+ drmModeFreeEncoder(encoder_);
225+ encoder_ = 0;
226+ }
227+
228+ if (!encoder_) {
229+ Log::error("Failed to find a suitable encoder\n");
230+ return false;
231+ }
232+
233+ if (!init_gbm()) {
234+ return false;
235+ }
236+
237+ crtc_ = drmModeGetCrtc(fd_, encoder_->crtc_id);
238+ if (!crtc_) {
239+ Log::error("Failed to get current CRTC\n");
240+ return false;
241+ }
242+
243+ signal(SIGINT, &DRMState::quit_handler);
244+
245+ return true;
246+}
247+
248+bool
249+DRMState::reset()
250+{
251+ if (bo_) {
252+ gbm_surface_release_buffer(surface_, bo_);
253+ }
254+
255+ bo_ = gbm_surface_lock_front_buffer(surface_);
256+ fb_ = fb_get_from_bo(bo_);
257+
258+ int status = drmModeSetCrtc(fd_, encoder_->crtc_id, fb_->fb_id, 0, 0,
259+ &connector_->connector_id, 1, mode_);
260+ if (status < 0) {
261+ Log::error("Failed to set CRTC: %d\n", status);
262+ return false;
263+ }
264+
265+ return true;
266+}
267+
268+
269+bool DRMState::should_quit_ = false;
270+
271+void
272+DRMState::quit_handler(int signo)
273+{
274+ Log::debug("Got SIGINT (%d).\n", signo);
275+ should_quit_ = true;
276+}
277+void
278+DRMState::page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data)
279+{
280+ unsigned int* waiting = reinterpret_cast<unsigned int*>(data);
281+ *waiting = 0;
282+ // Deal with unused parameters
283+ static_cast<void>(fd);
284+ static_cast<void>(frame);
285+ static_cast<void>(sec);
286+ static_cast<void>(usec);
287+}
288+
289+void
290+DRMState::do_flip()
291+{
292+ gbm_bo* next = gbm_surface_lock_front_buffer(surface_);
293+ fb_ = fb_get_from_bo(next);
294+ unsigned int waiting(1);
295+ int status = drmModePageFlip(fd_, encoder_->crtc_id, fb_->fb_id,
296+ DRM_MODE_PAGE_FLIP_EVENT, &waiting);
297+ if (status < 0) {
298+ Log::error("Failed to enqueue page flip: %d\n", status);
299+ return;
300+ }
301+
302+ fd_set fds;
303+ FD_ZERO(&fds);
304+ FD_SET(fd_, &fds);
305+ drmEventContext evCtx;
306+ evCtx.version = DRM_EVENT_CONTEXT_VERSION;
307+ evCtx.page_flip_handler = page_flip_handler;
308+
309+ while (waiting) {
310+ status = select(fd_ + 1, &fds, 0, 0, 0);
311+ if (status < 0) {
312+ // Most of the time, select() will return an error because the
313+ // user pressed Ctrl-C. So, only print out a message in debug
314+ // mode, and just check for the likely condition and release
315+ // the current buffer object before getting out.
316+ Log::debug("Error in select\n");
317+ if (should_quit()) {
318+ gbm_surface_release_buffer(surface_, bo_);
319+ bo_ = next;
320+ }
321+ return;
322+ }
323+ drmHandleEvent(fd_, &evCtx);
324+ }
325+
326+ gbm_surface_release_buffer(surface_, bo_);
327+ bo_ = next;
328+}
329+
330+void
331+DRMState::cleanup()
332+{
333+ // Restore CRTC state if necessary
334+ if (crtc_) {
335+ int status = drmModeSetCrtc(fd_, crtc_->crtc_id, crtc_->buffer_id,
336+ crtc_->x, crtc_->y, &connector_->connector_id,
337+ 1, &crtc_->mode);
338+ if (status < 0) {
339+ Log::error("Failed to restore original CRTC: %d\n", status);
340+ }
341+ drmModeFreeCrtc(crtc_);
342+ crtc_ = 0;
343+ }
344+ if (surface_) {
345+ gbm_surface_destroy(surface_);
346+ surface_ = 0;
347+ }
348+ if (dev_) {
349+ gbm_device_destroy(dev_);
350+ dev_ = 0;
351+ }
352+ if (connector_) {
353+ drmModeFreeConnector(connector_);
354+ connector_ = 0;
355+ }
356+ if (encoder_) {
357+ drmModeFreeEncoder(encoder_);
358+ encoder_ = 0;
359+ }
360+ if (resources_) {
361+ drmModeFreeResources(resources_);
362+ resources_ = 0;
363+ }
364+ if (fd_ > 0) {
365+ drmClose(fd_);
366+ }
367+ fd_ = 0;
368+ mode_ = 0;
369+}
370+
371+bool
372+CanvasDRM::init()
373+{
374+ Log::info("NOTE: The DRM canvas is still experimental and its behavior\n");
375+ Log::info(" is subject to change as GBM and modesetting behavior\n");
376+ Log::info(" evolves\n");
377+
378+ if (!drm_.init()) {
379+ Log::error("Failed to initialize the DRM canvas\n");
380+ drm_.cleanup();
381+ return false;
382+ }
383+
384+ width_ = drm_.mode_width();
385+ height_ = drm_.mode_height();
386+ resize_no_viewport(width_, height_);
387+
388+ if (!egl_.init_display(drm_.device(), visual_config_)) {
389+ return false;
390+ }
391+ if (!egl_.init_surface(drm_.surface())) {
392+ return false;
393+ }
394+ if (!egl_.valid()) {
395+ return false;
396+ }
397+
398+ return reset();
399+}
400+
401+
402+CanvasDRM::~CanvasDRM()
403+{
404+ drm_.cleanup();
405+}
406+
407+void
408+CanvasDRM::visible(bool /* visible */)
409+{
410+}
411+
412+void
413+CanvasDRM::clear()
414+{
415+ glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
416+#if USE_GL
417+ glClearDepth(1.0f);
418+#elif USE_GLESv2
419+ glClearDepthf(1.0f);
420+#endif
421+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
422+}
423+
424+void
425+CanvasDRM::update()
426+{
427+ Options::FrameEnd m = Options::frame_end;
428+
429+ if (m == Options::FrameEndDefault) {
430+ if (offscreen_)
431+ m = Options::FrameEndFinish;
432+ else
433+ m = Options::FrameEndSwap;
434+ }
435+
436+ switch(m) {
437+ case Options::FrameEndSwap:
438+ swap_buffers();
439+ break;
440+ case Options::FrameEndFinish:
441+ glFinish();
442+ break;
443+ case Options::FrameEndReadPixels:
444+ read_pixel(width_ / 2, height_ / 2);
445+ break;
446+ case Options::FrameEndNone:
447+ default:
448+ break;
449+ }
450+}
451+
452+void
453+CanvasDRM::print_info()
454+{
455+ make_current();
456+
457+ std::stringstream ss;
458+ ss << " OpenGL Information" << std::endl;
459+ ss << " GL_VENDOR: " << glGetString(GL_VENDOR) << std::endl;
460+ ss << " GL_RENDERER: " << glGetString(GL_RENDERER) << std::endl;
461+ ss << " GL_VERSION: " << glGetString(GL_VERSION) << std::endl;
462+ Log::info("%s", ss.str().c_str());
463+}
464+
465+Canvas::Pixel
466+CanvasDRM::read_pixel(int x, int y)
467+{
468+ uint8_t pixel[4];
469+ glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
470+ return Canvas::Pixel(pixel[0], pixel[1], pixel[2], pixel[3]);
471+}
472+
473+void
474+CanvasDRM::write_to_file(std::string &filename)
475+{
476+ char *pixels = new char[width_ * height_ * 4];
477+
478+ for (int i = 0; i < height_; i++) {
479+ glReadPixels(0, i, width_, 1, GL_RGBA, GL_UNSIGNED_BYTE,
480+ &pixels[(height_ - i - 1) * width_ * 4]);
481+ }
482+
483+ std::ofstream output (filename.c_str(), std::ios::out | std::ios::binary);
484+ output.write(pixels, 4 * width_ * height_);
485+
486+ delete [] pixels;
487+}
488+
489+bool
490+CanvasDRM::should_quit()
491+{
492+ return drm_.should_quit();
493+}
494+
495+void
496+CanvasDRM::resize(int width, int height)
497+{
498+ resize_no_viewport(width, height);
499+ glViewport(0, 0, width_, height_);
500+}
501+
502+/*********************
503+ * Protected methods *
504+ *********************/
505+
506+bool
507+CanvasDRM::supports_gl2()
508+{
509+ std::string gl_version_str(
510+ reinterpret_cast<const char*>(glGetString(GL_VERSION)));
511+ int gl_major = 0;
512+
513+ size_t point_pos(gl_version_str.find('.'));
514+
515+ if (point_pos != std::string::npos) {
516+ point_pos--;
517+
518+ size_t start_pos(gl_version_str.rfind(' ', point_pos));
519+ if (start_pos == std::string::npos)
520+ start_pos = 0;
521+ else
522+ start_pos++;
523+
524+ gl_major = Util::fromString<int>(
525+ gl_version_str.substr(start_pos, point_pos - start_pos + 1)
526+ );
527+ }
528+
529+ return gl_major >= 2;
530+}
531+
532+bool
533+CanvasDRM::make_current()
534+{
535+ if (!egl_.valid()) {
536+ Log::error("CanvasDRM: Invalid EGL state\n");
537+ return false;
538+ }
539+
540+ init_gl_extensions();
541+
542+ return true;
543+}
544+
545+bool
546+CanvasDRM::reset_context()
547+{
548+ return egl_.reset();
549+}
550+
551+void
552+CanvasDRM::swap_buffers()
553+{
554+ egl_.swap();
555+ drm_.do_flip();
556+}
557+
558+void
559+CanvasDRM::init_gl_extensions()
560+{
561+#if USE_GLESv2
562+ /*
563+ * Parse the extensions we care about from the extension string.
564+ * Don't even bother to get function pointers until we know the
565+ * extension is present.
566+ */
567+ std::string extString;
568+ const char* exts =
569+ reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
570+ if (exts)
571+ extString = exts;
572+
573+ if (extString.find("GL_OES_mapbuffer") != std::string::npos) {
574+ GLExtensions::MapBuffer = reinterpret_cast<PFNGLMAPBUFFEROESPROC>(
575+ eglGetProcAddress("glMapBufferOES"));
576+ GLExtensions::UnmapBuffer = reinterpret_cast<PFNGLUNMAPBUFFEROESPROC>(
577+ eglGetProcAddress("glUnmapBufferOES"));
578+ }
579+#elif USE_GL
580+ GLExtensions::MapBuffer = glMapBuffer;
581+ GLExtensions::UnmapBuffer = glUnmapBuffer;
582+#endif
583+}
584+
585+
586+/*******************
587+ * Private methods *
588+ *******************/
589+
590+void
591+CanvasDRM::resize_no_viewport(int width, int height)
592+{
593+ width_ = drm_.mode_width();
594+ height_ = drm_.mode_height();
595+
596+ if (!width_)
597+ width_ = width;
598+ if (!height_)
599+ height_ = height;
600+
601+ projection_ =
602+ LibMatrix::Mat4::perspective(60.0, width_ / static_cast<float>(height_),
603+ 1.0, 1024.0);
604+}
605
606=== added file 'src/canvas-drm.h'
607--- src/canvas-drm.h 1970-01-01 00:00:00 +0000
608+++ src/canvas-drm.h 2012-12-17 22:54:19 +0000
609@@ -0,0 +1,132 @@
610+//
611+// Copyright © 2012 Linaro Limited
612+//
613+// This file is part of the glmark2 OpenGL (ES) 2.0 benchmark.
614+//
615+// glmark2 is free software: you can redistribute it and/or modify it under the
616+// terms of the GNU General Public License as published by the Free Software
617+// Foundation, either version 3 of the License, or (at your option) any later
618+// version.
619+//
620+// glmark2 is distributed in the hope that it will be useful, but WITHOUT ANY
621+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
622+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
623+// details.
624+//
625+// You should have received a copy of the GNU General Public License along with
626+// glmark2. If not, see <http://www.gnu.org/licenses/>.
627+//
628+// Authors:
629+// Simon Que
630+// Jesse Barker
631+//
632+#ifndef GLMARK2_CANVAS_DRM_H_
633+#define GLMARK2_CANVAS_DRM_H_
634+
635+#include <cstring>
636+#include <gbm.h>
637+#include <drm.h>
638+#include <xf86drm.h>
639+#include <xf86drmMode.h>
640+
641+#include "canvas.h"
642+#include "egl-state.h"
643+
644+struct DRMFBState
645+{
646+ int fd;
647+ gbm_bo* bo;
648+ uint32_t fb_id;
649+};
650+
651+class DRMState
652+{
653+ static void page_flip_handler(int fd, unsigned int frame, unsigned int sec,
654+ unsigned int usec, void* data);
655+ static void fb_destroy_callback(gbm_bo* bo, void* data);
656+ static void quit_handler(int signum);
657+ static bool should_quit_;
658+ DRMFBState* fb_get_from_bo(gbm_bo* bo);
659+ bool init_gbm();
660+ int fd_;
661+ drmModeRes* resources_;
662+ drmModeConnector* connector_;
663+ drmModeEncoder* encoder_;
664+ drmModeCrtcPtr crtc_;
665+ drmModeModeInfo* mode_;
666+ gbm_device* dev_;
667+ gbm_surface* surface_;
668+ gbm_bo* bo_;
669+ DRMFBState* fb_;
670+
671+public:
672+ DRMState() :
673+ fd_(0),
674+ resources_(0),
675+ connector_(0),
676+ encoder_(0),
677+ mode_(0),
678+ dev_(0),
679+ surface_(0),
680+ bo_(0),
681+ fb_(0) {}
682+ ~DRMState() { cleanup(); }
683+ void cleanup();
684+ bool init();
685+ bool reset();
686+ void do_flip();
687+ bool should_quit() const { return should_quit_; }
688+ gbm_device* device() const { return dev_; }
689+ gbm_surface* surface() const { return surface_; }
690+ unsigned int mode_width() const
691+ {
692+ if (mode_) {
693+ return mode_->hdisplay;
694+ }
695+ return 0;
696+ }
697+ unsigned int mode_height() const
698+ {
699+ if (mode_) {
700+ return mode_->vdisplay;
701+ }
702+ return 0;
703+ }
704+};
705+
706+/**
707+ * Canvas for direct rendering with EGL.
708+ */
709+class CanvasDRM: public Canvas
710+{
711+public:
712+ CanvasDRM(int width, int height) :
713+ Canvas(width, height) {}
714+ ~CanvasDRM();
715+
716+ virtual bool init();
717+ virtual bool reset();
718+ virtual void visible(bool visible);
719+ virtual void clear();
720+ virtual void update();
721+ virtual void print_info();
722+ virtual Pixel read_pixel(int x, int y);
723+ virtual void write_to_file(std::string &filename);
724+ virtual bool should_quit();
725+ virtual void resize(int width, int height);
726+
727+protected:
728+ virtual bool make_current();
729+ virtual bool reset_context();
730+ virtual void swap_buffers();
731+ virtual bool supports_gl2();
732+
733+private:
734+ DRMState drm_;
735+ EGLState egl_;
736+
737+ void resize_no_viewport(int width, int height);
738+ void init_gl_extensions();
739+};
740+
741+#endif
742
743=== modified file 'src/main.cpp'
744--- src/main.cpp 2012-12-07 19:57:44 +0000
745+++ src/main.cpp 2012-12-17 22:54:19 +0000
746@@ -35,7 +35,9 @@
747 #include <iostream>
748 #include <fstream>
749
750-#if USE_GL
751+#if USE_DRM
752+#include "canvas-drm.h"
753+#elif USE_GL
754 #include "canvas-x11-glx.h"
755 #elif USE_GLESv2
756 #include "canvas-x11-egl.h"
757@@ -180,7 +182,9 @@
758 }
759
760 // Create the canvas
761-#if USE_GL
762+#if USE_DRM
763+ CanvasDRM canvas(Options::size.first, Options::size.second);
764+#elif USE_GL
765 CanvasX11GLX canvas(Options::size.first, Options::size.second);
766 #elif USE_GLESv2
767 CanvasX11EGL canvas(Options::size.first, Options::size.second);
768
769=== modified file 'src/wscript_build'
770--- src/wscript_build 2012-11-13 16:53:41 +0000
771+++ src/wscript_build 2012-12-17 22:54:19 +0000
772@@ -4,6 +4,8 @@
773 f.name.find('egl-') == -1]
774 gl_sources = ['canvas-x11.cpp', 'canvas-x11-glx.cpp']
775 glesv2_sources = ['canvas-x11.cpp', 'canvas-x11-egl.cpp', 'egl-state.cpp']
776+gl_drm_sources = ['canvas-drm.cpp', 'egl-state.cpp']
777+glesv2_drm_sources = ['canvas-drm.cpp', 'egl-state.cpp']
778 libmatrix_sources = [f for f in bld.path.ant_glob('libmatrix/*.cc')
779 if not f.name.endswith('test.cc')]
780 includes = ['.', 'scene-ideas', 'scene-terrain']
781@@ -47,3 +49,44 @@
782 includes = includes,
783 defines = ['USE_GLESv2', 'USE_EXCEPTIONS']
784 )
785+
786+if bld.env.USE_GL_DRM:
787+ bld(
788+ features = ['cxx', 'cxxstlib'],
789+ source = libmatrix_sources,
790+ target = 'matrix-drm',
791+ lib = ['m'],
792+ includes = ['.'],
793+ export_includes = 'libmatrix',
794+ defines = ['USE_DRM', '__GBM__', 'USE_GL', 'USE_EXCEPTIONS']
795+ )
796+ bld(
797+ features = ['cxx', 'cprogram'],
798+ source = common_sources + gl_drm_sources,
799+ target = 'glmark2-drm',
800+ use = ['egl', 'gl', 'matrix-drm', 'libpng12', 'drm', 'gbm'],
801+ lib = ['m', 'jpeg', 'dl'],
802+ includes = includes,
803+ defines = ['USE_DRM', '__GBM__', 'USE_GL']
804+ )
805+
806+if bld.env.USE_GLESv2_DRM:
807+ bld(
808+ features = ['cxx', 'cxxstlib'],
809+ source = libmatrix_sources,
810+ target = 'matrix-es2-drm',
811+ lib = ['m'],
812+ includes = ['.'],
813+ export_includes = 'libmatrix',
814+ defines = ['USE_DRM', '__GBM__', 'USE_GLESv2', 'USE_EXCEPTIONS']
815+ )
816+ bld(
817+ features = ['cxx', 'cprogram'],
818+ source = common_sources + glesv2_drm_sources,
819+ target = 'glmark2-es2-drm',
820+ use = ['egl', 'glesv2', 'matrix-es2-drm', 'libpng12', 'drm',
821+ 'gbm'],
822+ lib = ['m', 'jpeg', 'dl'],
823+ includes = includes,
824+ defines = ['USE_DRM', '__GBM__', 'USE_GLESv2']
825+ )
826
827=== modified file 'wscript'
828--- wscript 2012-11-26 19:29:33 +0000
829+++ wscript 2012-12-17 22:54:19 +0000
830@@ -20,6 +20,11 @@
831 default = False, help='build using OpenGL 2.0')
832 opt.add_option('--enable-glesv2', action='store_true', dest = 'glesv2',
833 default = False, help='build using OpenGL ES 2.0')
834+ opt.add_option('--enable-gl-drm', action='store_true', dest = 'gl_drm',
835+ default = False, help='build using OpenGL 2.0 without X')
836+ opt.add_option('--enable-glesv2-drm', action='store_true',
837+ dest = 'glesv2_drm',
838+ default = False, help='build using OpenGL ES 2.0 without X')
839 opt.add_option('--no-debug', action='store_false', dest = 'debug',
840 default = True, help='disable compiler debug information')
841 opt.add_option('--no-opt', action='store_false', dest = 'opt',
842@@ -30,8 +35,10 @@
843 help='path to additional data (models, shaders, textures)')
844
845 def configure(ctx):
846- if not Options.options.gl and not Options.options.glesv2:
847- ctx.fatal("You must configure using at least one of --enable-gl, --enable-glesv2")
848+ if not Options.options.gl and not Options.options.glesv2 and \
849+ not Options.options.gl_drm and not Options.options.glesv2_drm:
850+ ctx.fatal("You must configure using at least one of --enable-gl, " +
851+ "--enable-glesv2, --enable-gl-drm, --enable-glesv2-drm")
852
853 ctx.check_tool('gnu_dirs')
854 ctx.check_tool('compiler_cc')
855@@ -54,15 +61,22 @@
856 uselib = uselib, mandatory = True)
857
858 # Check required packages
859- req_pkgs = [('x11', 'x11'), ('libpng12', 'libpng12')]
860+ req_pkgs = [('libpng12', 'libpng12')]
861 for (pkg, uselib) in req_pkgs:
862 ctx.check_cfg(package = pkg, uselib_store = uselib,
863 args = '--cflags --libs', mandatory = True)
864
865 # Check optional packages
866- opt_pkgs = [('gl', 'gl', Options.options.gl),
867- ('egl', 'egl', Options.options.glesv2),
868- ('glesv2', 'glesv2', Options.options.glesv2)]
869+ opt_pkgs = [('x11', 'x11', Options.options.gl or Options.options.glesv2),
870+ ('gl', 'gl', Options.options.gl or Options.options.gl_drm),
871+ ('egl', 'egl', Options.options.glesv2 or
872+ Options.options.glesv2_drm),
873+ ('glesv2', 'glesv2', Options.options.glesv2 or
874+ Options.options.glesv2_drm),
875+ ('libdrm','drm', Options.options.gl_drm or
876+ Options.options.glesv2_drm),
877+ ('gbm','gbm', Options.options.gl_drm or
878+ Options.options.glesv2_drm)]
879 for (pkg, uselib, mandatory) in opt_pkgs:
880 ctx.check_cfg(package = pkg, uselib_store = uselib,
881 args = '--cflags --libs', mandatory = mandatory)
882@@ -94,6 +108,8 @@
883
884 ctx.env.USE_GL = Options.options.gl
885 ctx.env.USE_GLESv2 = Options.options.glesv2
886+ ctx.env.USE_GL_DRM = Options.options.gl_drm
887+ ctx.env.USE_GLESv2_DRM = Options.options.glesv2_drm
888
889 ctx.msg("Prefix", ctx.env.PREFIX, color = 'PINK')
890 ctx.msg("Data path", data_path, color = 'PINK')
891@@ -101,9 +117,13 @@
892 color = 'PINK');
893 if ctx.env.HAVE_EXTRAS:
894 ctx.msg("Extras path", Options.options.extras_path, color = 'PINK')
895- ctx.msg("Building GL2 version", "Yes" if ctx.env.USE_GL else "No",
896- color = 'PINK')
897- ctx.msg("Building GLESv2 version", "Yes" if ctx.env.USE_GLESv2 else "No",
898+ ctx.msg("Building X11 GL2 version", "Yes" if ctx.env.USE_GL else "No",
899+ color = 'PINK')
900+ ctx.msg("Building X11 GLESv2 version", "Yes" if ctx.env.USE_GLESv2 else "No",
901+ color = 'PINK')
902+ ctx.msg("Building DRM GL2 version", "Yes" if ctx.env.USE_GL_DRM else "No",
903+ color = 'PINK')
904+ ctx.msg("Building DRM GLESv2 version", "Yes" if ctx.env.USE_GLESv2_DRM else "No",
905 color = 'PINK')
906
907 def build(ctx):

Subscribers

People subscribed via source and target branches

to all changes: