Misc #204: Add glx_take_screenshot() & others

- Add glx_take_screenshot() for taking a screenshot. With ImageMagick
  the output data could be viewed in this way:

    display -size [SCREEN-WIDTH]x[SCREEN-HEIGHT] -depth 8 -flip
    rgb:[PATH]

  (#204)

- Add D-Bus command `opts_get string:paint_on_overlay_id` to get X
  Composite overlay window ID. (#204)

- Code cleanup.
This commit is contained in:
Richard Grenville 2014-09-07 18:58:09 +08:00
parent c5f45c8e3c
commit 8c88b4d6f1
4 changed files with 105 additions and 25 deletions

View File

@ -2208,6 +2208,9 @@ glx_render_(session_t *ps, const glx_texture_t *ptex,
void void
glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg); glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg);
unsigned char *
glx_take_screenshot(session_t *ps, int *out_length);
#ifdef CONFIG_VSYNC_OPENGL_GLSL #ifdef CONFIG_VSYNC_OPENGL_GLSL
GLuint GLuint
glx_create_shader(GLenum shader_type, const char *shader_str); glx_create_shader(GLenum shader_type, const char *shader_str);
@ -2484,6 +2487,28 @@ c2_matchd(session_t *ps, win *w, const c2_lptr_t *condlst,
#endif #endif
/**
* @brief Dump the given data to a file.
*/
static inline bool
write_binary_data(const char *path, const unsigned char *data, int length) {
if (!data)
return false;
FILE *f = fopen(path, "wb");
if (!f) {
printf_errf("(\"%s\"): Failed to open file for writing.", path);
return false;
}
int wrote_len = fwrite(data, sizeof(unsigned char), length, f);
fclose(f);
if (wrote_len != length) {
printf_errf("(\"%s\"): Failed to write all blocks: %d / %d", path,
wrote_len, length);
return false;
}
return true;
}
/** /**
* @brief Dump raw bytes in HEX format. * @brief Dump raw bytes in HEX format.
* *

View File

@ -1411,6 +1411,20 @@ xr_blur_dst(session_t *ps, Picture tgt_buffer,
return true; return true;
} }
/*
* WORK-IN-PROGRESS!
static void
xr_take_screenshot(session_t *ps) {
XImage *img = XGetImage(ps->dpy, get_tgt_window(ps), 0, 0,
ps->root_width, ps->root_height, AllPlanes, XYPixmap);
if (!img) {
printf_errf("(): Failed to get XImage.");
return NULL;
}
assert(0 == img->xoffset);
}
*/
/** /**
* Blur the background of a window. * Blur the background of a window.
*/ */
@ -7530,6 +7544,16 @@ session_destroy(session_t *ps) {
ps_g = NULL; ps_g = NULL;
} }
/*
static inline void
dump_img(session_t *ps) {
int len = 0;
unsigned char *d = glx_take_screenshot(ps, &len);
write_binary_data("/tmp/dump.raw", d, len);
free(d);
}
*/
/** /**
* Do the actual work. * Do the actual work.
* *

View File

@ -901,6 +901,11 @@ cdbus_process_opts_get(session_t *ps, DBusMessage *msg) {
cdbus_m_opts_get_do(fork_after_register, cdbus_reply_bool); cdbus_m_opts_get_do(fork_after_register, cdbus_reply_bool);
cdbus_m_opts_get_do(detect_rounded_corners, cdbus_reply_bool); cdbus_m_opts_get_do(detect_rounded_corners, cdbus_reply_bool);
cdbus_m_opts_get_do(paint_on_overlay, cdbus_reply_bool); cdbus_m_opts_get_do(paint_on_overlay, cdbus_reply_bool);
// paint_on_overlay_id: Get ID of the X composite overlay window
if (!strcmp("paint_on_overlay_id", target)) {
cdbus_reply_uint32(ps, msg, ps->overlay);
return true;
}
cdbus_m_opts_get_do(unredir_if_possible, cdbus_reply_bool); cdbus_m_opts_get_do(unredir_if_possible, cdbus_reply_bool);
cdbus_m_opts_get_do(unredir_if_possible_delay, cdbus_reply_int32); cdbus_m_opts_get_do(unredir_if_possible_delay, cdbus_reply_int32);
cdbus_m_opts_get_do(redirected_force, cdbus_reply_enum); cdbus_m_opts_get_do(redirected_force, cdbus_reply_enum);

View File

@ -1442,7 +1442,7 @@ glx_render_(session_t *ps, const glx_texture_t *ptex,
#endif #endif
argb = argb || (GLX_TEXTURE_FORMAT_RGBA_EXT == argb = argb || (GLX_TEXTURE_FORMAT_RGBA_EXT ==
ps->psglx->fbconfigs[ptex->depth]->texture_fmt); ps->psglx->fbconfigs[ptex->depth]->texture_fmt);
#ifdef CONFIG_VSYNC_OPENGL_GLSL #ifdef CONFIG_VSYNC_OPENGL_GLSL
const bool has_prog = pprogram && pprogram->prog; const bool has_prog = pprogram && pprogram->prog;
#endif #endif
@ -1754,6 +1754,32 @@ glx_swap_copysubbuffermesa(session_t *ps, XserverRegion reg) {
cxfree(rects); cxfree(rects);
} }
/**
* @brief Get tightly packed RGB888 data from GL front buffer.
*
* Don't expect any sort of decent performance.
*
* @returns tightly packed RGB888 data of the size of the screen,
* to be freed with `free()`
*/
unsigned char *
glx_take_screenshot(session_t *ps, int *out_length) {
int length = 3 * ps->root_width * ps->root_height;
GLint unpack_align_old = 0;
glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_align_old);
assert(unpack_align_old > 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
unsigned char *buf = cmalloc(length, unsigned char);
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, ps->root_width, ps->root_height, GL_RGB,
GL_UNSIGNED_BYTE, buf);
glReadBuffer(GL_BACK);
glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_align_old);
if (out_length)
*out_length = sizeof(unsigned char) * length;
return buf;
}
#ifdef CONFIG_VSYNC_OPENGL_GLSL #ifdef CONFIG_VSYNC_OPENGL_GLSL
GLuint GLuint
glx_create_shader(GLenum shader_type, const char *shader_str) { glx_create_shader(GLenum shader_type, const char *shader_str) {
@ -1847,34 +1873,34 @@ glx_create_program_end:
*/ */
GLuint GLuint
glx_create_program_from_str(const char *vert_shader_str, glx_create_program_from_str(const char *vert_shader_str,
const char *frag_shader_str) { const char *frag_shader_str) {
GLuint vert_shader = 0; GLuint vert_shader = 0;
GLuint frag_shader = 0; GLuint frag_shader = 0;
GLuint prog = 0; GLuint prog = 0;
if (vert_shader_str) if (vert_shader_str)
vert_shader = glx_create_shader(GL_VERTEX_SHADER, vert_shader_str); vert_shader = glx_create_shader(GL_VERTEX_SHADER, vert_shader_str);
if (frag_shader_str) if (frag_shader_str)
frag_shader = glx_create_shader(GL_FRAGMENT_SHADER, frag_shader_str); frag_shader = glx_create_shader(GL_FRAGMENT_SHADER, frag_shader_str);
{ {
GLuint shaders[2]; GLuint shaders[2];
int count = 0; int count = 0;
if (vert_shader) if (vert_shader)
shaders[count++] = vert_shader; shaders[count++] = vert_shader;
if (frag_shader) if (frag_shader)
shaders[count++] = frag_shader; shaders[count++] = frag_shader;
assert(count <= sizeof(shaders) / sizeof(shaders[0])); assert(count <= sizeof(shaders) / sizeof(shaders[0]));
if (count) if (count)
prog = glx_create_program(shaders, count); prog = glx_create_program(shaders, count);
} }
if (vert_shader) if (vert_shader)
glDeleteShader(vert_shader); glDeleteShader(vert_shader);
if (frag_shader) if (frag_shader)
glDeleteShader(frag_shader); glDeleteShader(frag_shader);
return prog; return prog;
} }
#endif #endif