Implement "dump raw frame buffer to stdout"
Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
This commit is contained in:
parent
acaef93bd8
commit
75baf054e5
2 changed files with 119 additions and 3 deletions
118
shadermeh.c
118
shadermeh.c
|
@ -21,14 +21,55 @@ static double diff_timespec(const struct timespec *time1,
|
||||||
+ (time1->tv_nsec - time0->tv_nsec) / 1000000000.0;
|
+ (time1->tv_nsec - time0->tv_nsec) / 1000000000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void convert_for_ffmpeg(const uint8_t *in, uint8_t *out,
|
||||||
|
size_t width, size_t height)
|
||||||
|
{
|
||||||
|
size_t x, y;
|
||||||
|
|
||||||
|
for (y = 0; y < height; ++y) {
|
||||||
|
const uint8_t *src = in + y * width * 4;
|
||||||
|
uint8_t *dst = out + (height - 1 - y) * width * 3;
|
||||||
|
|
||||||
|
for (x = 0; x < width; ++x) {
|
||||||
|
*(dst++) = *(src++);
|
||||||
|
*(dst++) = *(src++);
|
||||||
|
*(dst++) = *(src++);
|
||||||
|
++src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_retry(int fd, const void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
while (size > 0) {
|
||||||
|
int ret = write(fd, buffer, size);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
perror("write");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
size -= ret;
|
||||||
|
buffer = (const char *)buffer + ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct option long_opts[] = {
|
static const struct option long_opts[] = {
|
||||||
{ "width", required_argument, NULL, 'w' },
|
{ "width", required_argument, NULL, 'w' },
|
||||||
{ "height", required_argument, NULL, 'h' },
|
{ "height", required_argument, NULL, 'h' },
|
||||||
{ "shader", required_argument, NULL, 's' },
|
{ "shader", required_argument, NULL, 's' },
|
||||||
|
{ "to-stdout", no_argument, NULL, 'S' },
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *short_opts = "w:h:s:";
|
static const char *short_opts = "w:h:s:S";
|
||||||
|
|
||||||
static const char *usage_str =
|
static const char *usage_str =
|
||||||
"shadermeh OPTIONS...\n"
|
"shadermeh OPTIONS...\n"
|
||||||
|
@ -38,6 +79,8 @@ static const char *usage_str =
|
||||||
" --width, -w <pixels>\n"
|
" --width, -w <pixels>\n"
|
||||||
" --height, -h <pixels>\n"
|
" --height, -h <pixels>\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" --to-stdout, -S\n"
|
||||||
|
"\n"
|
||||||
" --shader, -s <shader file>\n"
|
" --shader, -s <shader file>\n"
|
||||||
"\n";
|
"\n";
|
||||||
|
|
||||||
|
@ -46,10 +89,12 @@ int main(int argc, char **argv)
|
||||||
GLuint u_iResolution, u_iTime, u_iTimeDelta, u_iFrame;
|
GLuint u_iResolution, u_iTime, u_iTimeDelta, u_iFrame;
|
||||||
struct timespec start, frame_start, frame_end;
|
struct timespec start, frame_start, frame_end;
|
||||||
unsigned int width, height, iFrame = 0;
|
unsigned int width, height, iFrame = 0;
|
||||||
|
void *fb32 = NULL, *fb24 = NULL;
|
||||||
const char *shader_file = NULL;
|
const char *shader_file = NULL;
|
||||||
|
GLuint vao, vbo, fbo, fbo_tex;
|
||||||
GLint major, minor, prog;
|
GLint major, minor, prog;
|
||||||
float iTime, iTimeDelta;
|
float iTime, iTimeDelta;
|
||||||
GLuint vao, vbo;
|
bool to_stdout = false;
|
||||||
window *wnd;
|
window *wnd;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -72,6 +117,9 @@ int main(int argc, char **argv)
|
||||||
case 's':
|
case 's':
|
||||||
shader_file = optarg;
|
shader_file = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'S':
|
||||||
|
to_stdout = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fputs(usage_str, stderr);
|
fputs(usage_str, stderr);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
@ -84,11 +132,28 @@ int main(int argc, char **argv)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (to_stdout) {
|
||||||
|
fb32 = calloc(1, width * height * 4);
|
||||||
|
if (!fb32) {
|
||||||
|
perror("allocating scratch framebuffer");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fb24 = calloc(1, width * height * 3);
|
||||||
|
if (!fb24) {
|
||||||
|
perror("allocating scratch framebuffer");
|
||||||
|
free(fb32);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/********** create window and make context current **********/
|
/********** create window and make context current **********/
|
||||||
wnd = window_create(width, height, "shader meh...");
|
wnd = window_create(width, height, "shader meh...");
|
||||||
|
|
||||||
if (!wnd) {
|
if (!wnd) {
|
||||||
fputs("failed to create window", stderr);
|
fputs("failed to create window", stderr);
|
||||||
|
free(fb32);
|
||||||
|
free(fb24);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +166,8 @@ int main(int argc, char **argv)
|
||||||
if (glewInit() != GLEW_OK) {
|
if (glewInit() != GLEW_OK) {
|
||||||
fputs("glewInit() error", stderr);
|
fputs("glewInit() error", stderr);
|
||||||
window_destroy(wnd);
|
window_destroy(wnd);
|
||||||
|
free(fb32);
|
||||||
|
free(fb24);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,12 +215,34 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
|
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
|
||||||
|
|
||||||
|
/******************** framebuffer object ********************/
|
||||||
|
if (to_stdout) {
|
||||||
|
glGenFramebuffers(1, &fbo);
|
||||||
|
glGenTextures(1, &fbo_tex);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, fbo_tex);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
||||||
|
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||||
|
fbo_tex, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/******************** drawing loop ********************/
|
/******************** drawing loop ********************/
|
||||||
while (window_handle_events()) {
|
while (window_handle_events()) {
|
||||||
|
/* render image to FBO */
|
||||||
|
if (to_stdout)
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
|
||||||
clock_gettime(CLOCK_MONOTONIC_RAW, &frame_start);
|
clock_gettime(CLOCK_MONOTONIC_RAW, &frame_start);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
if (!to_stdout)
|
||||||
window_swap_buffers(wnd);
|
window_swap_buffers(wnd);
|
||||||
|
|
||||||
clock_gettime(CLOCK_MONOTONIC_RAW, &frame_end);
|
clock_gettime(CLOCK_MONOTONIC_RAW, &frame_end);
|
||||||
|
|
||||||
iFrame += 1;
|
iFrame += 1;
|
||||||
|
@ -163,6 +252,23 @@ int main(int argc, char **argv)
|
||||||
glUniform1f(u_iTimeDelta, iTimeDelta);
|
glUniform1f(u_iTimeDelta, iTimeDelta);
|
||||||
glUniform1f(u_iTime, iTime);
|
glUniform1f(u_iTime, iTime);
|
||||||
glUniform1ui(u_iFrame, iFrame);
|
glUniform1ui(u_iFrame, iFrame);
|
||||||
|
|
||||||
|
if (to_stdout) {
|
||||||
|
/* get image from FBO */
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, fbo_tex);
|
||||||
|
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA,
|
||||||
|
GL_UNSIGNED_BYTE, fb32);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
/* convert to 24 bps and dump to stdout */
|
||||||
|
convert_for_ffmpeg(fb32, fb24, width, height);
|
||||||
|
|
||||||
|
if (write_retry(STDOUT_FILENO, fb24,
|
||||||
|
width * height * 3)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************** cleanup ********************/
|
/******************** cleanup ********************/
|
||||||
|
@ -173,7 +279,15 @@ int main(int argc, char **argv)
|
||||||
glDeleteVertexArrays(1, &vao);
|
glDeleteVertexArrays(1, &vao);
|
||||||
glDeleteProgram(prog);
|
glDeleteProgram(prog);
|
||||||
|
|
||||||
|
if (to_stdout) {
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glDeleteFramebuffers(1, &fbo);
|
||||||
|
glDeleteTextures(1, &fbo_tex);
|
||||||
|
}
|
||||||
|
|
||||||
window_make_current(NULL);
|
window_make_current(NULL);
|
||||||
|
free(fb32);
|
||||||
|
free(fb24);
|
||||||
window_destroy(wnd);
|
window_destroy(wnd);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,13 @@
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
#include <GL/glx.h>
|
#include <GL/glx.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
Loading…
Reference in a new issue