Update with current status
[gnash.git] / librender / testr.cpp
blob5fa0ff55de7b6b52ad02778cc4dab75d5d9a10ad
1 //
2 // Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
23 #include <iostream>
24 #include <string>
25 #include <cstdlib>
26 #include <vector>
27 #include <sstream>
28 #include <map>
29 #include <cassert>
30 #include <regex.h>
31 #include <boost/assign/list_of.hpp>
32 #include <boost/date_time/date.hpp>
33 #include <boost/date_time/posix_time/posix_time.hpp>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
38 #include "log.h"
39 #include "dejagnu.h"
40 #include "SWFMatrix.h"
41 #include "Renderer.h"
42 #include "Transform.h"
43 #include "ShapeRecord.h"
44 #include "CachedBitmap.h"
45 #include "GnashVaapiImage.h"
46 #include "GnashVaapiImageProxy.h"
47 #include "boost/date_time/posix_time/posix_time.hpp"
49 #ifdef RENDERER_AGG
50 #include "agg/Renderer_agg.h"
51 #endif
52 #ifdef RENDERER_OPENGL
53 #include "opengl/Renderer_ogl.h"
54 #endif
55 #ifdef RENDERER_OPENVG
56 #include "openvg/OpenVGRenderer.h"
57 #include <VG/vgu.h>
58 #ifdef HAVE_VG_VGEXT_H
59 # include <VG/vgext.h>
60 #else
61 # include <VG/ext.h>
62 #endif
63 #endif
64 #ifdef RENDERER_GLES1
65 #include "opengles1/Renderer_gles1.h"
66 #endif
67 #ifdef RENDERER_GLES2
68 #include "opengles2/Renderer_gles2.h"
69 #endif
70 #ifdef RENDERER_CAIRO
71 #include "cairo/Renderer_cairo.h"
72 #endif
73 #ifdef HAVE_EGL_EGL_H
74 # include <EGL/egl.h>
75 #else
76 # error "This file needs EGL"
77 #endif
79 #ifdef BUILD_EGL_DEVICE
80 # include <egl/eglDevice.h>
81 #endif
82 #ifdef BUILD_DIRECTFB_DEVICE
83 # include <directfb/directfb.h>
84 #endif
85 #ifdef BUILD_X11_DEVICE
86 # include <x11/X11Device.h>
87 #endif
89 TestState runtest;
91 using namespace gnash;
92 using namespace renderer;
93 using namespace std;
94 using namespace boost::posix_time;
96 void test_device(Renderer *renderer, const std::string &type);
97 void test_renderer(Renderer *renderer, const std::string &type);
98 void test_geometry(Renderer *renderer, const std::string &type);
99 void test_iterators(Renderer *renderer, const std::string &type);
101 // The debug log used by all the gnash libraries.
102 static LogFile& dbglogfile = LogFile::getDefaultInstance();
104 //------------------------------------------------------------
106 // Simple class to do nanosecond based timing for performance analysis
107 class Timer {
108 public:
109 Timer(const std::string &name, bool flag)
111 _print = flag;
112 _name = name;
113 start();
115 Timer(const std::string &name) : _print(false) { _name = name; start(); }
116 Timer() : _print(false) { start(); }
117 ~Timer()
119 stop();
120 if (_print) {
121 cerr << "Total time for " << _name << " was: " << elapsed() << endl;
125 void start() {
126 _starttime = boost::posix_time::microsec_clock::local_time();
129 void stop() {
130 _stoptime = boost::posix_time::microsec_clock::local_time();
133 std::string elapsed() {
134 stringstream ss;
135 time_duration td = _stoptime - _starttime;
136 ss << td.total_nanoseconds() << "ns elapsed";
137 return ss.str();
139 void setName(const std::string &name) { _name = name; };
140 std::string &getName() { return _name; };
142 private:
143 bool _print;
144 std::string _name;
145 boost::posix_time::ptime _starttime;
146 boost::posix_time::ptime _stoptime;
150 main(int argc, char *argv[])
152 // FIXME: for now, always run verbose till this supports command line args
153 dbglogfile.setVerbosity();
155 const char *pixelformat = "RGB24";
156 int fd = 0;
158 #ifdef BUILD_RAWFB_DEVICE_XXX
159 rawfb::RawFBDevice rawfb(argc, argv);
160 fd = rawfb.getHandle();
161 #endif // BUILD_RAWFB_DEVICE
163 #if defined(BUILD_EGL_DEVICE) && !defined(BUILD_X11_DEVICE)
164 // Setup EGL, OpenVG needs it
165 EGLDevice egl(argc, argv);
166 egl.bindClient(GnashDevice::OPENVG);
167 fd = open("/dev/fb0", O_RDWR);
168 egl.attachWindow(fd);
169 #endif // BUILD_EGL_DEVICE
171 #ifdef BUILD_X11_DEVICE
172 // Setup EGL, OpenVG needs it
173 EGLDevice egl;
174 //egl.setAttrib(1);
175 egl.initDevice(argc, argv);
176 int vid = egl.getNativeVisual();
177 egl.bindClient(GnashDevice::OPENVG);
179 // Create an X11 device for the display. This is for libMesa
180 // where we can also run OpenVG on the desktop.
181 x11::X11Device x11(vid);
182 //x11.initDevice(argc, argv);
183 x11.createWindow("TestR", 0, 0, 640, 480);
185 // This is the window that gets rendered in
186 Window win = x11.getHandle();
187 if (win) {
188 egl.attachWindow(win);
189 } else {
190 log_error(_("Couldn't get Drawable window from X11"));
191 exit(1);
193 // Set initial projection/viewing transformation.
194 // We can't be sure we'll get a ConfigureNotify event when the window
195 // first appears.
196 #if 0
197 if (reshape) {
198 reshape(640, 480);
200 #endif
201 x11.eventLoop(10);
202 std::cerr << "Hello World!" << std::endl;
203 x11.eventLoop(10);
204 #endif
206 #ifdef RENDERER_AGG
207 Timer tagg("AGG");
208 Renderer *renderer1 = create_Renderer_agg(pixelformat);
209 // The methods were moved to the glue API
210 // if (renderer1) {
211 // test_device(renderer1, "EGL");
212 // test_device(renderer1, "DIRECTFB");
213 // test_device(renderer1, "X11");
214 // }
215 if (renderer1) {
216 test_renderer(renderer1, "AGG");
217 test_geometry(renderer1, "AGG");
218 test_iterators(renderer1, "AGG");
219 tagg.stop();
221 cerr << "AGG tests took " << tagg.elapsed() << endl << endl;
222 #endif
224 #ifdef RENDERER_OPENVG
225 Timer tovg("OpenVG");
226 Renderer *renderer2 = renderer::openvg::create_handler(pixelformat);
227 // EGLDevice *ovg = dynamic_cast<EGLDevice *>(renderer2);
228 // if (ovg) {
229 // ovg->initDevice(0, 0);
230 // // ovg->attachWindow(*(reinterpret_cast<EGLNativeWindowType *>(canvas)));
231 // ovg->attachWindow(0);
232 if (renderer2) {
233 test_renderer(renderer2, "OpenVG");
234 test_geometry(renderer2, "OpenVG");
235 test_iterators(renderer2, "OpenVG");
236 } else {
237 cerr << "ERROR: No OpenVG renderer to test!" << endl;
239 tovg.stop();
240 cerr << "OpenVG tests took " << tovg.elapsed() << endl;
241 #endif
243 #if 0
244 #ifdef RENDERER_GLES1
245 Timer tgles1("OpenGLES1");
246 Renderer *renderer3 = renderer::gles1::create_handler(pixelformat);
247 if (renderer3) {
248 test_renderer(renderer3, "OpenGLES1");
249 test_geometry(renderer3, "OpenGLES1");
250 test_iterators(renderer3, "OpenGLES1");
251 } else {
252 cerr << "ERROR: No OpenGLES1 renderer to test!" << endl;
254 tgles1.stop();
255 cerr << "OpenGLES1 tests took " << tgles1.elapsed() << endl;
256 #endif
258 #ifdef RENDERER_GLES2
259 Timer tgles2("OpenGLES2");
260 Renderer *renderer4 = renderer::gles2::create_handler(pixelformat);
261 if (renderer4) {
262 test_renderer(renderer4, "OpenGLES2");
263 test_geometry(renderer4, "OpenGLES2");
264 test_iterators(renderer4, "OpenGLES2");
265 } else {
266 cerr << "ERROR: No OpenGLES2 renderer to test!" << endl;
268 tgles2.stop();
269 cerr << "OpenGLES2 tests took " << tgles2.elapsed() << endl;
270 #endif
272 #ifdef RENDERER_CAIRO
273 Timer tcairo("Cairo");
274 Renderer *renderer5 = renderer::cairo::create_handler();
275 if (renderer5) {
276 test_renderer(renderer5, "Cairo");
277 test_geometry(renderer5, "Cairo");
278 test_iterators(renderer5, "Cairo");
279 } else {
280 cerr << "ERROR: No Cairo renderer to test!" << endl;
282 tcairo.stop();
283 cerr << "Cairo tests took " << tcairo.elapsed() << endl;
284 #endif
286 #ifdef RENDERER_OPENGL
287 Timer tgl("OpenGL");
288 Renderer *renderer6 = renderer::opengl::create_handler(true);
289 if (renderer6) {
290 test_renderer(renderer6, "OpenGL");
291 test_geometry(renderer6, "OpenGL");
292 test_iterators(renderer6, "OpenGL");
293 } else {
294 cerr << "ERROR: No OpenGL renderer to test!" << endl;
296 tgl.stop();
297 cerr << "OpenGL tests took " << tgl.elapsed() << endl;
298 #endif
299 #endif
302 // Each Renderer has an associated display device, currently EGL
303 // for OpenVG, OpenGLES1, and OpenGLES2. The DirectFB device is
304 // also available for these three renderers. The EGL device can
305 // also be run under X11 using the Mesa libraries. Both EGL and
306 // DirectFB are primarily for framebuffers. While all of the methods
307 // of each device class are available to the Renderer, most aren't
308 // exposed with more accesors beyond these for manipulating the
309 // device setting itself.
310 void
311 test_device(Renderer *renderer, const std::string &type)
313 cout << endl << "Testing " << type << " Device" << endl;
315 #if 0
316 std::unique_ptr<renderer::GnashDevice::dtype_t[]> devs = renderer->probeDevices();
317 if (devs) {
318 runtest.pass("Renderer::probeDevices()");
319 } else {
320 runtest.fail("Renderer::probeDevices()");
322 // Be default, there should be no device associated with this
323 // renderer yet.
324 if (renderer->getDevice() == GnashDevice::GNASH_NODEV) {
325 runtest.pass("Renderer::getDevice()");
326 } else {
327 runtest.fail("Renderer::getDevice()");
330 // Set to a device and see if it's axctually set
331 renderer->setDevice(GnashDevice::X11);
332 if (renderer->getDevice() == GnashDevice::X11) {
333 runtest.pass("Renderer::setDevice()");
334 } else {
335 runtest.fail("Renderer::setDevice()");
338 // reset to the original value so we don't screw up future tests
339 renderer->resetDevice();
340 #endif
343 void
344 test_renderer(Renderer *renderer, const std::string &type)
346 cout << "Testing " << type << " Renderer" << endl;
347 // Timer trend("Renderer Tests", true);
349 if (!renderer) {
350 runtest.unresolved("No renderer to test!");
351 return;
354 if (renderer > 0) {
355 runtest.pass("Got Renderer");
356 } else {
357 runtest.fail("Couldn't get Renderer");
360 if (!renderer->description().empty()) {
361 if (renderer->description() == type) {
362 runtest.pass("description is correct");
363 } else {
364 runtest.fail("description is wrong");
366 } else {
367 runtest.fail("Couldn't get description!");
370 #if 0
371 if (renderer->getBitsPerPixel()) {
372 runtest.pass("getBitsPerPixel()");
373 } else {
374 runtest.fail("getBitsPerPixel()");
376 #endif
378 image::GnashImage *frame1 = new image::ImageRGBA(10, 12);
379 std::unique_ptr<image::GnashImage> im1(frame1);
380 CachedBitmap *cb = renderer->createCachedBitmap(im1);
381 if (cb) {
382 image::GnashImage &gi = cb->image();
383 if ((gi.width() == 10) && (gi.height() == 12)) {
384 runtest.pass("createCachedBitmap()");
385 } else {
386 runtest.fail("createCachedBitmap()");
388 } else {
389 runtest.unresolved("createCachedBitmap()");
392 #if 0
393 // FIXME: initTestBuffer() is going away, replaced by the fake
394 // framebuffer code.
395 // Initializes the renderer for off-screen rendering used by the testsuite.
396 if (renderer->initTestBuffer(10, 10)) {
397 runtest.pass("initTestBuffer()");
398 } else {
399 runtest.fail("initTestBuffer()");
401 #endif
403 /// @coords an array of 16-bit signed integer coordinates. Even indices
404 /// (and 0) are x coordinates, while uneven ones are y coordinates.
405 /// @vertex_count the number of x-y coordinates (vertices).
406 /// @color the color to be used to draw the line strip.
407 /// @mat the SWFMatrix to be used to transform the vertices.
408 std::uint16_t x = 10;
409 std::uint16_t y = 10;
410 std::uint16_t h = 10;
411 std::vector<point> box = boost::assign::list_of
412 (point(x, y))
413 (point(x, y + h));
415 rgba color(0, 0, 0, 255);
416 SWFMatrix mat;
417 mat.set_scale_rotation(1, 3, 0);
419 Timer tdrawline("drawline");
420 renderer->drawLine(box, color, mat);
421 tdrawline.stop();
423 // if (1) {
424 // runtest.pass("drawLine()");
425 // } else {
426 // runtest.fail("drawLine()");
427 // }
428 runtest.unresolved(std::string("drawLine() ") + tdrawline.elapsed());
430 //drawVideoFrame(image::GnashImage* frame, const Transform& xform, const SWFRect* bounds, bool smooth);
431 #if 0
432 image::GnashImage *frame;
433 const Transform xform;
434 const SWFRect bounds;
435 bool smooth;
436 Timer tdrawvideo("drawVideoFrame");
437 renderer->drawVideoFrame(frame, xform, bounds, smooth);
438 tdrawvideo.stop();
439 #endif
440 runtest.untested("drawVideoFrame()");
442 point *corners = 0;
443 size_t corner_count = 0;
444 rgba fill(0, 0, 0, 255);;
445 rgba outline(0, 0, 0, 255);;
446 bool masked = true;
447 Timer tdrawpoly("drawPoly");
448 renderer->draw_poly(corners, corner_count, fill, outline, mat, masked);
449 tdrawpoly.stop();
450 runtest.unresolved(std::string("drawPoly() ") + tdrawpoly.elapsed());
452 // SWF::ShapeRecord shape;
453 SWFMatrix mat2(0x10000, 0x0, 0x0, 0x10000, 0x0, 0x0);
454 SWFCxForm cxform;
455 //(0x100, 0x100, 0x100, 0x100, 0x0, 0x0, 0x0, 0x0);
456 Transform xform(mat2, cxform);
457 SWF::ShapeRecord shape;
458 // _bounds = {0x80000000, 0x7fffffff,
459 // 0x80000000, 0x80000000,
460 // 0x80000000, 0x80000000}}
461 Timer drawshape("drawShape");
462 renderer->drawShape(shape, xform);
463 runtest.unresolved("drawShape()");
464 drawshape.stop();
466 // SWF::ShapeRecord rec;
467 // rgba color;
468 // SWFMatrix mat;
469 // Timer drawGlyph("drawGlyph");
470 // renderer->drawGlyph(rec, color, mat);
471 runtest.untested("drawGlyph()");
472 // drawglyph.stop();
474 #if 0
475 std::unique_ptr<IOChannel> io;
476 FileType ftype;
477 Timer renderi("renderToImage");
478 renderer->renderToImage(io, ftype);
479 renderi.stop();
480 #endif
481 runtest.untested("renderToImage()");
483 CachedBitmap *bitmap = 0;
484 image::GnashImage *frame2 = new image::ImageRGBA(10, 10);
485 std::unique_ptr<image::GnashImage> im(frame2);
486 Timer cbit("createCachedBitmap");
487 bitmap = renderer->createCachedBitmap(im);
488 cbit.stop();
489 if (bitmap) {
490 runtest.pass(std::string("createCachedBitmap() ") + cbit.elapsed());
491 } else {
492 runtest.fail(std::string("createCachedBitmap() ") + cbit.elapsed());
496 void
497 test_geometry(Renderer *renderer, const std::string &type)
499 cout << "\t" << type << " geometry tests" << endl;
501 if (!renderer) {
502 runtest.unresolved("No renderer to test!");
503 return;
506 int x = 10;
507 int y = 10;
508 geometry::Point2d nz(200, 0);
509 geometry::Point2d z(x, y);
510 geometry::Range2d<int> pixelbounds;
511 geometry::Range2d<int> worldbounds;
512 Timer tpixtow("pixel_to_world(int, int)");
513 z = renderer->pixel_to_world(x, y);
514 tpixtow.stop();
516 if ((z.x >= 199) || (z.y >= 199)) {
517 runtest.pass(std::string("pixel_to_world(int, int) ") + tpixtow.elapsed());
518 } else {
519 runtest.fail(std::string("pixel_to_world(int, int) ") + tpixtow.elapsed());
522 #if 0
523 Timer tpixtow2("pixel_to_world(pixelbounds)");
524 worldbounds = renderer->pixel_to_world(pixelbounds);
525 tpixtow2.stop();
526 if (worldbounds.isNull()) {
527 runtest.pass(std::string("pixel_to_world(geometry::Range2d<int>) ") + tpixtow2.elapsed());
528 } else {
529 runtest.fail(std::string("pixel_to_world(geometry::Range2d<int>) ") + tpixtow2.elapsed());
531 #else
532 runtest.untested("pixel_to_world(geometry::Range2d<int>)");
533 #endif
535 Timer twtop("world_to_pixel(geometry::Range2d<int>)");
536 pixelbounds = renderer->world_to_pixel(worldbounds);
537 twtop.stop();
538 if (pixelbounds.isNull()) {
539 runtest.pass(std::string("world_to_pixel(geometry::Range2d<int>) ") + twtop.elapsed());
540 } else {
541 runtest.fail(std::string("world_to_pixel(geometry::Range2d<int>) ") + twtop.elapsed());
544 SWFRect bounds;
545 Timer tbounds1("bounds_in_clipping_area(SWFRect)");
546 bool ret = renderer->bounds_in_clipping_area(bounds);
547 tbounds1.stop();
548 if (ret) {
549 runtest.pass(std::string("bounds_in_clipping_area(SWFRect) ") + tbounds1.elapsed());
550 } else {
551 runtest.fail(std::string("bounds_in_clipping_area(SWFRect) ") + tbounds1.elapsed());
554 InvalidatedRanges ranges;
555 Timer tbounds2("bounds_in_clipping_area(InvalidatedRanges)");
556 ret = renderer->bounds_in_clipping_area(ranges);
557 tbounds2.stop();
558 if (!ret) {
559 runtest.pass(std::string("bounds_in_clipping_area(InvalidatedRanges) ") + tbounds2.elapsed());
560 } else {
561 runtest.fail(std::string("bounds_in_clipping_area(InvalidatedRanges) ") + tbounds2.elapsed());
564 Timer tbounds3("bounds_in_clipping_area(geometry::Range2d<int>)");
565 ret = renderer->bounds_in_clipping_area(pixelbounds);
566 tbounds3.stop();
567 if (!ret) {
568 runtest.pass(std::string("bounds_in_clipping_area(geometry::Range2d<int>) ") + tbounds3.elapsed());
569 } else {
570 runtest.fail(std::string("bounds_in_clipping_area(geometry::Range2d<int>) ") + tbounds3.elapsed());
575 // Machinery for delayed images rendering (e.g. Xv with YV12 or VAAPI)
577 void
578 test_iterators(Renderer *renderer, const std::string &type)
580 cout << "\t"<< type << " iterator tests" << endl;
582 if (!renderer) {
583 runtest.unresolved("No renderer to test!");
584 return;
587 Renderer::RenderImages::iterator fit = renderer->getFirstRenderImage();
588 Renderer::RenderImages::iterator lit = renderer->getLastRenderImage();
589 // When there are no images, the first and last are the same obviously
590 if (fit == lit) {
591 runtest.pass("getFirstRenderImage()");
592 } else {
593 runtest.fail("getFirstRenderImage()");
596 #if 0
597 geometry::Point2d a(1, 2);
598 geometry::Point2d c(3, 4);
599 Renderer::RenderImage image;
600 image::GnashImage *frame = new image::ImageRGBA(10, 10);
601 // gnash::GnashVaapiImage *foo = static_cast<gnash::GnashVaapiImage *>(frame);
602 // gnash::GnashVaapiImageProxy *bar = new gnash::GnashVaapiImageProxy(foo, a.x, a.y, c.x - a.x, c.y - a.y);
603 std::unique_ptr<image::GnashImage> rgba(frame);
604 // image.reset(new gnash::GnashVaapiImageProxy(foo, a.x, a.y, c.x - a.x, c.y - a.y));
606 renderer->addRenderImage(image);
607 // image.reset(new gnash::GnashVaapiImageProxy(foo, a.x, a.y, c.x - a.x, c.y - a.y));
608 renderer->addRenderImage(image);
609 #endif
611 fit = renderer->getFirstRenderImage();
612 lit = renderer->getLastRenderImage();
613 // When there are no images, the first and last are the same obviously
614 if (fit != lit) {
615 runtest.pass("addRenderImage()");
616 } else {
617 runtest.fail("addRenderImage()");
620 #if 0
621 typedef std::shared_ptr<GnashVaapiImageProxy> RenderImage;
622 typedef std::vector<RenderImage> RenderImages;
624 // Get first render image
625 virtual RenderImages::iterator getFirstRenderImage()
626 { return _render_images.begin(); }
627 virtual RenderImages::const_iterator getFirstRenderImage() const
628 { return _render_images.begin(); }
630 // Get last render image
631 virtual RenderImages::iterator getLastRenderImage()
632 { return _render_images.end(); }
633 virtual RenderImages::const_iterator getLastRenderImage() const
634 { return _render_images.end(); }
635 #endif
638 #if 0
639 FIXME:
640 add tests for
641 Renderer_ovg::createBitmapInfo(std::unique_ptr<GnashImage> im)
642 #endif
644 // Local Variables:
645 // mode: C++
646 // indent-tabs-mode: nil
647 // End: