Skip to content

Commit

Permalink
Initial source commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
cubicool committed Aug 28, 2014
1 parent f983515 commit 863a28b
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 22 deletions.
23 changes: 2 additions & 21 deletions .gitignore
@@ -1,21 +1,2 @@
# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app
build
.syntastic
28 changes: 28 additions & 0 deletions CMakeLists.txt
@@ -0,0 +1,28 @@
PROJECT(cairo-gl-sdl2)

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

SET(CMAKE_CXX_FLAGS "-W -Wall -Wno-unused-parameter -Werror -O3 -std=c++11")

INCLUDE(FindPkgConfig)

PKG_CHECK_MODULES(CAIRO REQUIRED cairo)
PKG_CHECK_MODULES(SDL2 REQUIRED sdl2)

INCLUDE_DIRECTORIES(
${CAIRO_INCLUDE_DIRS}
${SDL2_INCLUDE_DIRS}
)

LINK_DIRECTORIES(
${CAIRO_LIBRARY_DIRS}
${SDL2_LIBRARY_DIRS}
)

ADD_EXECUTABLE(cairo-gl-sdl2 "src/main.cpp")

TARGET_LINK_LIBRARIES(cairo-gl-sdl2
${CAIRO_LIBRARIES}
${SDL2_LIBRARIES}
)

7 changes: 6 additions & 1 deletion README.md
@@ -1,4 +1,9 @@
cairo-gl-sdl2
=============

Cairo, SDL2, and GL/GLES2 tests.
This project is a test bed for using Cairo, SDL2, and GL/GLES2 together.
It differs from existing projects in that it uses the new (ACTUAL) OpenGL
Cairo backend, which has recently received a lot of development attention.

I have found it to be almost twice as fast as the image backend, though
it can be up to triple the speed in some cases.
154 changes: 154 additions & 0 deletions src/SDL2.hpp
@@ -0,0 +1,154 @@
#ifndef SDL2_HPP
#define SDL2_HPP

#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>
#include <tuple>
#include <iostream>

class SDL2Window {
public:
typedef std::tuple<int, int> size_type;

SDL2Window():
_window(nullptr),
_context(nullptr) {
}

bool init(int width, int height, unsigned int flags=0) {
if(SDL_Init(SDL_INIT_VIDEO)) {
std::cerr << "SDL_Init failed!" << std::endl;

return false;
}

_window = SDL_CreateWindow(
"Cairo+OpenGL+SDL2",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
width,
height,
SDL_WINDOW_OPENGL | flags
);

if(!_window) {
std::cerr << "SDL_CreateWindow failed!" << std::endl;

return false;
}

_context = SDL_GL_CreateContext(_window);

if(!_context) {
std::cerr << "SDL_GL_CreateContext failed." << std::endl;

return false;
}

SDL_VERSION(&_info.version);

if(!SDL_GetWindowWMInfo(_window, &_info)) {
std::cout << SDL_FALSE << std::endl;
std::cerr << "SDL_GetWindowWMInfofailed." << std::endl;
std::cerr << SDL_GetError() << std::endl;

return false;
}

return true;
}

double main() {
double frames = 0.0;
bool running = true;
Uint32 start = SDL_GetTicks();

SDL_Event event;

while(running) {
while(SDL_PollEvent(&event)) {
if(_mainQuit(event)) running = false;
}

// DO STUFF

SDL_GL_SwapWindow(_window);

frames += 1.0;
}

SDL_GL_DeleteContext(_context);
SDL_DestroyWindow(_window);
SDL_Quit();

return frames / static_cast<double>(SDL_GetTicks() - start);
}

size_type getSize() const {
int w = 0;
int h = 0;

SDL_GetWindowSize(_window, &w, &h);

return std::make_tuple(w, h);
}

int getWidth() const {
int w = 0;

std::tie(w, std::ignore) = getSize();

return w;
}

int getHeight() const {
int h = 0;

std::tie(std::ignore, h) = getSize();

return h;
}

bool isFullscreen() const {
return SDL_GetWindowFlags(_window) & SDL_WINDOW_FULLSCREEN;
}

void setFullscreen(bool go_fullscreen) const {
SDL_SetWindowFullscreen(_window, go_fullscreen ? 1 : 0);
}

const char* getTitle() const {
return SDL_GetWindowTitle(_window);
}

void setTitle(const std::string& title) {
SDL_SetWindowTitle(_window, title.c_str());
}

Display* getDisplay() {
return _info.info.x11.display;
};

SDL_GLContext getContext() {
// if(!SDL_GL_MakeCurrent(_window, _context)) return nullptr;

return _context;
}

protected:
inline bool _mainQuit(const SDL_Event& event) const {
if(event.type == SDL_QUIT || (
event.type == SDL_KEYUP &&
event.key.keysym.sym == SDLK_ESCAPE
)) return true;

return false;
}

SDL_Window* _window;
SDL_GLContext _context;
SDL_SysWMinfo _info;
};

#endif

121 changes: 121 additions & 0 deletions src/main.cpp
@@ -0,0 +1,121 @@
#include "SDL2.hpp"

#include <chrono>
#include <string>
#include <cstdlib>
#include <iomanip>
#include <cairo.h>
#include <cairo-gl.h>

// Size of the surface.
const unsigned int WIDTH = 512;
const unsigned int HEIGHT = 512;

inline void draw(cairo_t* cr) {
cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0);
cairo_paint(cr);
cairo_arc(cr, 256.0, 256.0, 200.0, 0.0, 2.0 * 3.14159);
cairo_set_source_rgba(cr, 1.0, 0.0, 0.5, 0.5);
cairo_fill(cr);
}

int main(int argc, char** argv) {
if(argc != 3) {
std::cerr
<< "Usage: " << argv[0]
<< " num_draws [image | gl | gl_texture]" << std::endl
;

return 1;
}

SDL2Window window;

if(!window.init(WIDTH, HEIGHT, SDL_WINDOW_HIDDEN)) {
std::cerr << "Couldn't initialize SDL2 window; fatal." << std::endl;

return 2;
}

cairo_device_t* device = cairo_glx_device_create(
window.getDisplay(),
reinterpret_cast<GLXContext>(window.getContext())
);

if(!device) {
std::cerr << "Couldn't create device; fatal." << std::endl;

return 3;
}

// Variable initialization. In the future, I'll need to setup
// the OpenGL texture to use here as well.
auto num_draws = std::atoi(argv[1]);
auto method = std::string(argv[2]);
cairo_surface_t* surface = nullptr;

if(method == "image" ) surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32,
WIDTH,
HEIGHT
);

else if(method == "gl") surface = cairo_gl_surface_create(
device,
CAIRO_CONTENT_COLOR_ALPHA,
WIDTH,
HEIGHT
);

// TODO: Implemente cairo_gl_surface_create_for_texture test.
// else if(method == "gl_texture")

else {
std::cerr << "Unknown surface type '" << method << "'; fatal." << std::endl;

return 4;
}

if(!surface) {
std::cerr << "Couldn't create surface; fatal." << std::endl;

return 5;
}

std::cout << "Performing " << num_draws << " iterations: " << std::flush;

auto start = std::chrono::system_clock::now();
auto last_tick = 0;

for(auto i = 0; i < num_draws; i++) {
cairo_t* cr = cairo_create(surface);

draw(cr);

cairo_destroy(cr);

// This is a completely wretched way of doing a progress meter,
// but it's the best I'm willing to do for now.
double pct = (static_cast<double>(i) / static_cast<double>(num_draws)) * 100.0;

if(pct >= last_tick + 10.0) {
std::cout << "+" << std::flush;

last_tick = pct;
}
}

auto end = std::chrono::system_clock::now();

std::cout
<< " done! ("
<< std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()
<< "ms)" << std::endl
;

cairo_surface_destroy(surface);
cairo_device_destroy(device);

return 0;
}

0 comments on commit 863a28b

Please sign in to comment.