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;
|
||||
}
|
||||
|
||||
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[] = {
|
||||
{ "width", required_argument, NULL, 'w' },
|
||||
{ "height", required_argument, NULL, 'h' },
|
||||
{ "shader", required_argument, NULL, 's' },
|
||||
{ "to-stdout", no_argument, NULL, 'S' },
|
||||
{ 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 =
|
||||
"shadermeh OPTIONS...\n"
|
||||
|
@ -38,6 +79,8 @@ static const char *usage_str =
|
|||
" --width, -w <pixels>\n"
|
||||
" --height, -h <pixels>\n"
|
||||
"\n"
|
||||
" --to-stdout, -S\n"
|
||||
"\n"
|
||||
" --shader, -s <shader file>\n"
|
||||
"\n";
|
||||
|
||||
|
@ -46,10 +89,12 @@ int main(int argc, char **argv)
|
|||
GLuint u_iResolution, u_iTime, u_iTimeDelta, u_iFrame;
|
||||
struct timespec start, frame_start, frame_end;
|
||||
unsigned int width, height, iFrame = 0;
|
||||
void *fb32 = NULL, *fb24 = NULL;
|
||||
const char *shader_file = NULL;
|
||||
GLuint vao, vbo, fbo, fbo_tex;
|
||||
GLint major, minor, prog;
|
||||
float iTime, iTimeDelta;
|
||||
GLuint vao, vbo;
|
||||
bool to_stdout = false;
|
||||
window *wnd;
|
||||
int i;
|
||||
|
||||
|
@ -72,6 +117,9 @@ int main(int argc, char **argv)
|
|||
case 's':
|
||||
shader_file = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
to_stdout = true;
|
||||
break;
|
||||
default:
|
||||
fputs(usage_str, stderr);
|
||||
return EXIT_FAILURE;
|
||||
|
@ -84,11 +132,28 @@ int main(int argc, char **argv)
|
|||
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 **********/
|
||||
wnd = window_create(width, height, "shader meh...");
|
||||
|
||||
if (!wnd) {
|
||||
fputs("failed to create window", stderr);
|
||||
free(fb32);
|
||||
free(fb24);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -101,6 +166,8 @@ int main(int argc, char **argv)
|
|||
if (glewInit() != GLEW_OK) {
|
||||
fputs("glewInit() error", stderr);
|
||||
window_destroy(wnd);
|
||||
free(fb32);
|
||||
free(fb24);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -148,12 +215,34 @@ int main(int argc, char **argv)
|
|||
|
||||
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 ********************/
|
||||
while (window_handle_events()) {
|
||||
/* render image to FBO */
|
||||
if (to_stdout)
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &frame_start);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
if (!to_stdout)
|
||||
window_swap_buffers(wnd);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &frame_end);
|
||||
|
||||
iFrame += 1;
|
||||
|
@ -163,6 +252,23 @@ int main(int argc, char **argv)
|
|||
glUniform1f(u_iTimeDelta, iTimeDelta);
|
||||
glUniform1f(u_iTime, iTime);
|
||||
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 ********************/
|
||||
|
@ -173,7 +279,15 @@ int main(int argc, char **argv)
|
|||
glDeleteVertexArrays(1, &vao);
|
||||
glDeleteProgram(prog);
|
||||
|
||||
if (to_stdout) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
glDeleteTextures(1, &fbo_tex);
|
||||
}
|
||||
|
||||
window_make_current(NULL);
|
||||
free(fb32);
|
||||
free(fb24);
|
||||
window_destroy(wnd);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
#include <GL/gl.h>
|
||||
#include <GL/glx.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
typedef struct {
|
||||
|
|
Loading…
Reference in a new issue