Browse Source

Cairo version that actually works properly

master
Wesley Kerfoot 5 years ago
parent
commit
9a57e30ce3
  1. 262
      blit_cairo.c
  2. 89
      blit_opengl.c

262
blit_cairo.c

@ -0,0 +1,262 @@
#include <assert.h>
#include <cairo-xcb.h>
#include <cairo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <xcb/xcb.h>
void
print_cairo_format(cairo_format_t format) {
switch (format) {
case CAIRO_FORMAT_INVALID:
printf("Invalid\n");
break;
case CAIRO_FORMAT_ARGB32:
printf("ARGB32\n");
break;
case CAIRO_FORMAT_RGB24:
printf("ARGB32\n");
break;
case CAIRO_FORMAT_A8:
printf("A8\n");
break;
case CAIRO_FORMAT_A1:
printf("A1\n");
break;
case CAIRO_FORMAT_RGB16_565:
printf("RGB16_565\n");
break;
case CAIRO_FORMAT_RGB30:
printf("RGB30\n");
break;
default:
break;
}
}
static xcb_visualtype_t*
findVisual(xcb_connection_t *display,
xcb_visualid_t visual) {
/* Taken from here https://cairographics.org/cookbook/xcbsurface.c/ */
/* This function basically searches for a xcb_visualtype_t given a visual ID */
xcb_screen_iterator_t screen_iter = xcb_setup_roots_iterator(xcb_get_setup(display));
for(; screen_iter.rem; xcb_screen_next(&screen_iter)) {
/* Iterate over the screens available */
xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(screen_iter.data);
for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
/* Iterate over the depths allowed on this screen */
xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
/* depth_iter.data = the number of visuals available */
for (; visual_iter.rem; xcb_visualtype_next(&visual_iter)) {
/* Iterate over all of the visuals available */
if (visual == visual_iter.data->visual_id) {
printf("%u bits per rgb value\n", visual_iter.data->bits_per_rgb_value);
return visual_iter.data;
}
}
}
}
return NULL;
}
xcb_screen_t*
allocScreen(xcb_connection_t *display) {
/* Gets a screen from the display connection */
const xcb_setup_t *setup = xcb_get_setup(display);
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
xcb_screen_t *screen = iter.data;
return screen;
}
void
swapBuffers(cairo_t *front_cr,
cairo_surface_t *backbuffer_surface,
unsigned char v,
int height) {
int stride = cairo_image_surface_get_stride(backbuffer_surface);
unsigned char *data = cairo_image_surface_get_data(backbuffer_surface);
memset(data, v, stride*height);
cairo_surface_flush(backbuffer_surface);
cairo_set_source_surface(front_cr,
backbuffer_surface,
0,
0);
cairo_paint(front_cr);
cairo_surface_flush(backbuffer_surface);
}
cairo_surface_t*
allocFrontBuf(xcb_connection_t *display,
xcb_drawable_t drawable,
xcb_screen_t *screen,
int width,
int height) {
cairo_surface_t *surface = cairo_xcb_surface_create(display,
drawable,
findVisual(display, screen->root_visual),
width,
height);
printf("Stride = %d\n", cairo_image_surface_get_stride(surface));
return surface;
}
cairo_surface_t*
allocBackBuf(int width,
int height) {
cairo_format_t format = CAIRO_FORMAT_RGB24;
cairo_surface_t *surface = cairo_image_surface_create(format,
width,
height);
int stride = cairo_image_surface_get_stride(surface);
printf("Stride for image = %d\n", stride);
/* might not be needed */
cairo_surface_flush(surface);
return surface;
}
xcb_connection_t*
allocDisplay() {
/* Get a display to use */
/* Currently just uses the default display */
xcb_connection_t *display = xcb_connect(NULL, NULL);
if (display == NULL) {
fprintf(stderr, "Could not open the display! :(\n");
exit(1);
}
return display;
}
xcb_window_t
allocWindow(xcb_connection_t *display,
xcb_screen_t *screen,
uint16_t width,
uint16_t height) {
/* Create the window */
xcb_window_t window = xcb_generate_id(display);
xcb_cw_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
/* Define all the events we want to handle with xcb */
/* XCB_EVENT_MASK_EXPOSURE is the "exposure" event */
/* I.e. it fires when our window shows up on the screen */
uint32_t valwin[2] = {screen->white_pixel, XCB_EVENT_MASK_EXPOSURE};
xcb_create_window(display,
XCB_COPY_FROM_PARENT, /* depth (same as root) */
window,
screen->root, /* parent window */
0, /* x */
0, /* y */
width,/* width */
height,/* height */
10, /* border_width */
XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */
screen->root_visual, /* visual */
mask, /* value mask, used for events */
valwin); /* masks, used for events */
return window;
}
static struct timespec
genSleep(time_t sec,
long nanosec) {
struct timespec t;
t.tv_sec = sec;
t.tv_nsec = nanosec;
return t;
}
int
main (void) {
/* Used to handle the event loop */
struct timespec req = genSleep(0, 20000000);
struct timespec rem = genSleep(0, 0);
/* Open up the display */
xcb_connection_t *display = allocDisplay();
/* Get a handle to the screen */
xcb_screen_t *screen = allocScreen(display);
int window_height = screen->height_in_pixels;
int window_width = screen->width_in_pixels;
/* Create a window */
xcb_window_t window =
allocWindow(display,
screen,
window_width,
window_height);
/* Map the window to the display */
xcb_map_window(display, window);
/* Allocate front buffer (X drawable) */
cairo_surface_t *frontbuffer_surface =
allocFrontBuf(display,
window,
screen,
window_width,
window_height);
cairo_t *front_cr = cairo_create(frontbuffer_surface);
/* Allocate backbuffer (raw pixel buffer) */
cairo_surface_t *backbuffer_surface =
allocBackBuf(window_width, window_height);
cairo_t *back_cr = cairo_create(backbuffer_surface);
unsigned char v = 0;
while (1) {
swapBuffers(front_cr,
backbuffer_surface,
v,
window_height);
xcb_flush(display);
nanosleep(&req, &rem);
v++;
}
pause();
cairo_destroy(back_cr);
cairo_surface_destroy(backbuffer_surface);
cairo_destroy(front_cr);
cairo_surface_destroy(frontbuffer_surface);
return 0;
}

89
blit_opengl.c

@ -1,5 +1,6 @@
#include <GL/gl.h>
#include <GL/glx.h>
#include <GL/glu.h>
#include <X11/Xlib-xcb.h> /* for XGetXCBConnection, link with libX11-xcb */
#include <X11/Xlib.h>
#include <assert.h>
@ -52,24 +53,18 @@ static int visual_attribs[] = {
*/
#define RECEIVE_EVENT(ev) (ev->response_type & ~0x80)
void draw(GLint offset) {
/* This is needed because now the contents of `drawable` are undefined */
printf("Drawing!\n");
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 500, 500, 0.0, 0.0, 1.0);
glBegin(GL_POINTS);
for (int i = 0; i < 100; i++) {
glVertex2i(offset, i);
}
glEnd();
void draw(uint16_t height,
uint16_t width) {
// Draw a Red 1x1 Square centered at origin
glBegin(GL_QUADS); // Each set of 4 vertices form a quad
glColor3f(1.0f, 0.0f, 0.0f); // Red
glVertex2f(-0.5f, -0.5f); // x, y
glVertex2f( 0.5f, -0.5f);
glVertex2f( 0.5f, 0.5f);
glVertex2f(-0.5f, 0.5f);
glEnd();
glFlush(); // Render now
}
static struct timespec
@ -85,20 +80,30 @@ int
message_loop(Display *display,
xcb_connection_t *xcb_display,
xcb_window_t window,
xcb_screen_t *screen,
GLXDrawable drawable) {
int running = 1;
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
GLint offset = 0;
GLint x_offset = 0;
/* Used to handle the event loop */
struct timespec req = genSleep(0, 20000000);
struct timespec rem = genSleep(0, 0);
xcb_expose_event_t *expose;
uint16_t window_height = screen->height_in_pixels;
uint16_t window_width = screen->width_in_pixels;
int exposed = 0;
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer (background)
while (running) {
/* Poll for events */
@ -111,7 +116,13 @@ message_loop(Display *display,
// running = 0;
break;
case XCB_EXPOSE:
expose = (xcb_expose_event_t *)event;
window_height = expose->height;
window_width = expose->width;
printf("Got expose event\n");
exposed = 1;
break;
default:
break;
@ -119,28 +130,29 @@ message_loop(Display *display,
free(event);
}
draw(offset);
offset++;
/* This is where the magic happens */
/* This call will NOT block.*/
/* It will be sync'd with vertical refresh */
glXSwapBuffers(display, drawable);
nanosleep(&req, &rem);
}
if (exposed) {
draw(window_width, window_height);
/* This is where the magic happens */
/* This call will NOT block.*/
/* It will be sync'd with vertical refresh */
glXSwapBuffers(display, drawable);
nanosleep(&req, &rem);
}
}
return 0;
}
int
setup_message_loop(Display* display,
xcb_connection_t *xcb_display,
int default_screen,
xcb_screen_t *screen) {
xcb_connection_t *xcb_display,
int default_screen,
xcb_screen_t *screen) {
int visualID = 0;
uint16_t width = 500;
uint16_t height = 500;
uint16_t width = screen->width_in_pixels;
uint16_t height = screen->height_in_pixels;
/* Query framebuffer configurations that match visual_attribs */
GLXFBConfig *fb_configs = 0;
@ -192,8 +204,7 @@ setup_message_loop(Display* display,
display,
fb_config,
window,
0
);
0);
if (!window) {
xcb_destroy_window(xcb_display, window);
@ -224,6 +235,7 @@ setup_message_loop(Display* display,
int retval = message_loop(display,
xcb_display,
window,
screen,
drawable);
/* Cleanup */
@ -383,7 +395,10 @@ main(void) {
xcb_screen_t *screen = getScreen(xcb_display, default_screen);
/* Initialize window and OpenGL context, run main loop and deinitialize */
int retval = setup_message_loop(display, xcb_display, default_screen, screen);
int retval = setup_message_loop(display,
xcb_display,
default_screen,
screen);
/* Cleanup */
XCloseDisplay(display);

Loading…
Cancel
Save