# HG changeset patch # User Mike Pavone # Date 1382936882 25200 # Node ID dffc07104b099165067aae43d9dcd6d2da112125 # Parent db5880d8ea034595ffcfbb16b0746a92c9644f1c# Parent 193ca779988e5e2b6ade98eaed8ed2ce26aa93d2 Merged OpenGL branch diff -r db5880d8ea03 -r dffc07104b09 Makefile --- a/Makefile Thu Oct 03 21:22:05 2013 -0700 +++ b/Makefile Sun Oct 27 22:08:02 2013 -0700 @@ -1,4 +1,4 @@ -LIBS=sdl +LIBS=sdl glew gl LDFLAGS=-lm `pkg-config --libs $(LIBS)` ifdef DEBUG CFLAGS=-ggdb -std=gnu99 `pkg-config --cflags-only-I $(LIBS)` -Wreturn-type -Werror=return-type diff -r db5880d8ea03 -r dffc07104b09 blastem.c --- a/blastem.c Thu Oct 03 21:22:05 2013 -0700 +++ b/blastem.c Sun Oct 27 22:08:02 2013 -0700 @@ -278,9 +278,9 @@ adjust_int_cycle(context, v_context); if (address) { if (break_on_sync) { - break_on_sync = 0; - debugger(context, address); - } + break_on_sync = 0; + debugger(context, address); + } if (save_state) { save_state = 0; while (!z_context->pc) @@ -1507,7 +1507,7 @@ context->master_clock = ((uint64_t)context->normal_clock * (uint64_t)percent) / 100; while (context->ym->current_cycle != context->psg->cycles) { sync_sound(context, context->psg->cycles + MCLKS_PER_PSG); - } +} ym_adjust_master_clock(context->ym, context->master_clock); psg_adjust_master_clock(context->psg, context->master_clock); } @@ -1773,7 +1773,7 @@ char * romfname = NULL; FILE *address_log = NULL; char * statefile = NULL; - uint8_t fullscreen = 0; + uint8_t fullscreen = 0, use_gl = 0; for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch(argv[i][1]) { @@ -1783,6 +1783,9 @@ case 'f': fullscreen = 1; break; + case 'g': + use_gl = 1; + break; case 'l': address_log = fopen("address.log", "w"); break; @@ -1885,7 +1888,7 @@ fps = 50; } if (!headless) { - render_init(width, height, title, fps, fullscreen); + render_init(width, height, title, fps, fullscreen, use_gl); } vdp_context v_context; genesis_context gen; diff -r db5880d8ea03 -r dffc07104b09 default.f.glsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/default.f.glsl Sun Oct 27 22:08:02 2013 -0700 @@ -0,0 +1,14 @@ +#version 110 + +uniform sampler2D textures[2]; + +varying vec2 texcoord; + +void main() +{ + gl_FragColor = mix( + texture2D(textures[0], texcoord), + texture2D(textures[1], vec2(texcoord.x, texcoord.y - 1.0/512.0)), + sin((texcoord.y * 512.0 - 0.75) * 3.14159265359) / 2.0 + 0.5 + ); +} diff -r db5880d8ea03 -r dffc07104b09 default.v.glsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/default.v.glsl Sun Oct 27 22:08:02 2013 -0700 @@ -0,0 +1,10 @@ +#version 110 + +attribute vec2 pos; +varying vec2 texcoord; + +void main() +{ + gl_Position = vec4(pos, 0.0, 1.0); + texcoord = pos * vec2(320.0/1024.0, 240.0/-512.0) + vec2(320.0/1024.0, 240.0/512.0); +} diff -r db5880d8ea03 -r dffc07104b09 render.h --- a/render.h Thu Oct 03 21:22:05 2013 -0700 +++ b/render.h Sun Oct 27 22:08:02 2013 -0700 @@ -1,6 +1,6 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #ifndef RENDER_H_ @@ -9,9 +9,17 @@ #include "vdp.h" #include "psg.h" #include "ym2612.h" + +typedef struct { + void *oddbuf; + void *evenbuf; + int stride; +} surface_info; + uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b); +void render_alloc_surfaces(vdp_context * context); uint8_t render_depth(); -void render_init(int width, int height, char * title, uint32_t fps, uint8_t fullscreen); +void render_init(int width, int height, char * title, uint32_t fps, uint8_t fullscreen, uint8_t use_gl); void render_context(vdp_context * context); void render_wait_quit(vdp_context * context); void render_wait_psg(psg_context * context); diff -r db5880d8ea03 -r dffc07104b09 render_sdl.c --- a/render_sdl.c Thu Oct 03 21:22:05 2013 -0700 +++ b/render_sdl.c Sun Oct 27 22:08:02 2013 -0700 @@ -1,6 +1,6 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #include @@ -9,9 +9,14 @@ #include "blastem.h" #include "io.h" +#ifndef DISABLE_OPENGL +#include +#endif + SDL_Surface *screen; uint8_t render_dbg = 0; uint8_t debug_pal = 0; +uint8_t render_gl; uint32_t last_frame = 0; @@ -85,7 +90,104 @@ uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) { - return SDL_MapRGB(screen->format, r, g, b); + if (render_gl) { + return 255 << 24 | r << 16 | g << 8 | b; + } else { + return SDL_MapRGB(screen->format, r, g, b); + } +} + +GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], at_pos; + +const GLfloat vertex_data[] = { + -1.0f, -1.0f, + 1.0f, -1.0f, + -1.0f, 1.0f, + 1.0f, 1.0f +}; + +const GLushort element_data[] = {0, 1, 2, 3}; + +GLuint load_shader(char * fname, GLenum shader_type) +{ + FILE * f = fopen(fname, "r"); + if (!f) { + fprintf(stderr, "Failed to open shader file %s for reading\n", fname); + return 0; + } + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + GLchar * text = malloc(fsize); + if (fread(text, 1, fsize, f) != fsize) { + fprintf(stderr, "Error reading from shader file %s\n", fname); + free(text); + return 0; + } + GLuint ret = glCreateShader(shader_type); + glShaderSource(ret, 1, (const GLchar **)&text, (const GLint *)&fsize); + free(text); + glCompileShader(ret); + GLint compile_status, loglen; + glGetShaderiv(ret, GL_COMPILE_STATUS, &compile_status); + if (!compile_status) { + fprintf(stderr, "Shader %s failed to compile\n", fname); + glGetShaderiv(ret, GL_INFO_LOG_LENGTH, &loglen); + text = malloc(loglen); + glGetShaderInfoLog(ret, loglen, NULL, text); + fputs(text, stderr); + free(text); + glDeleteShader(ret); + return 0; + } + return ret; +} + +void render_alloc_surfaces(vdp_context * context) +{ + if (render_gl) { + context->oddbuf = context->framebuf = malloc(320 * 240 * 4 * 2); + memset(context->oddbuf, 0, 320 * 240 * 4 * 2); + context->evenbuf = ((char *)context->oddbuf) + 320 * 240 * 4; + glGenTextures(3, textures); + for (int i = 0; i < 3; i++) + { + glBindTexture(GL_TEXTURE_2D, textures[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (i < 2) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, i ? context->evenbuf : context->oddbuf); + } else { + uint32_t blank = 255 << 24; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); + } + } + glGenBuffers(2, buffers); + glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW); + vshader = load_shader("default.v.glsl", GL_VERTEX_SHADER); + fshader = load_shader("default.f.glsl", GL_FRAGMENT_SHADER); + program = glCreateProgram(); + glAttachShader(program, vshader); + glAttachShader(program, fshader); + glLinkProgram(program); + GLint link_status; + glGetProgramiv(program, GL_LINK_STATUS, &link_status); + if (!link_status) { + fputs("Failed to link shader program\n", stderr); + exit(1); + } + un_textures[0] = glGetUniformLocation(program, "textures[0]"); + un_textures[1] = glGetUniformLocation(program, "textures[1]"); + at_pos = glGetAttribLocation(program, "pos"); + } else { + context->oddbuf = context->framebuf = malloc(320 * 240 * screen->format->BytesPerPixel * 2); + context->evenbuf = ((char *)context->oddbuf) + 320 * 240 * screen->format->BytesPerPixel; + } } uint8_t render_depth() @@ -95,62 +197,98 @@ char * caption = NULL; -void render_init(int width, int height, char * title, uint32_t fps, uint8_t fullscreen) +void render_init(int width, int height, char * title, uint32_t fps, uint8_t fullscreen, uint8_t use_gl) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { - fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); - exit(1); - } - atexit(SDL_Quit); - atexit(render_close_audio); - printf("width: %d, height: %d\n", width, height); - uint32_t flags = SDL_ANYFORMAT; - if (fullscreen) { - flags |= SDL_FULLSCREEN | SDL_HWSURFACE | SDL_DOUBLEBUF; - } else { - flags |= SDL_SWSURFACE; - } - screen = SDL_SetVideoMode(width, height, 32, flags); - if (!screen) { - fprintf(stderr, "Unable to get SDL surface: %s\n", SDL_GetError()); - exit(1); - } - if (screen->format->BytesPerPixel != 2 && screen->format->BytesPerPixel != 4) { - fprintf(stderr, "BlastEm requires a 16-bit or 32-bit surface, SDL returned a %d-bit surface\n", screen->format->BytesPerPixel * 8); - exit(1); - } - SDL_WM_SetCaption(title, title); + fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); + exit(1); + } + atexit(SDL_Quit); + atexit(render_close_audio); + printf("width: %d, height: %d\n", width, height); + uint32_t flags = SDL_ANYFORMAT; + +#ifndef DISABLE_OPENGL + if (use_gl) + { + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + flags = SDL_OPENGL; + if (fullscreen) { + flags |= SDL_FULLSCREEN; + } + } else { +#else + { +#endif + if (fullscreen) { + flags |= SDL_FULLSCREEN | SDL_HWSURFACE | SDL_DOUBLEBUF; + } else { + flags |= SDL_SWSURFACE; + } + } + screen = SDL_SetVideoMode(width, height, 32, flags); + if (!screen) { + fprintf(stderr, "Unable to get SDL surface: %s\n", SDL_GetError()); + exit(1); + } + if (!use_gl && screen->format->BytesPerPixel != 2 && screen->format->BytesPerPixel != 4) { + fprintf(stderr, "BlastEm requires a 16-bit or 32-bit surface, SDL returned a %d-bit surface\n", screen->format->BytesPerPixel * 8); + exit(1); + } +#ifndef DISABLE_OPENGL + //TODO: fallback on standard rendering if OpenGL 2.0 is unavailable or if init fails + if (use_gl) + { + GLenum res = glewInit(); + if (res != GLEW_OK) + { + fprintf(stderr, "Initialization of GLEW failed with code %d\n", res); + exit(1); + } + if (!GLEW_VERSION_2_0) + { + fputs("OpenGL 2.0 is unable, falling back to standard SDL rendering\n", stderr); + exit(1); + } + } + render_gl = use_gl; +#endif + SDL_WM_SetCaption(title, title); caption = title; - min_delay = 0; - for (int i = 0; i < 100; i++) { - uint32_t start = SDL_GetTicks(); - SDL_Delay(1); - uint32_t delay = SDL_GetTicks()-start; - if (delay > min_delay) { - min_delay = delay; - } - } - if (!min_delay) { - min_delay = 1; - } - printf("minimum delay: %d\n", min_delay); - - frame_delay = 1000/fps; - - audio_mutex = SDL_CreateMutex(); - psg_cond = SDL_CreateCond(); - ym_cond = SDL_CreateCond(); - audio_ready = SDL_CreateCond(); - - SDL_AudioSpec desired, actual; + min_delay = 0; + for (int i = 0; i < 100; i++) { + uint32_t start = SDL_GetTicks(); + SDL_Delay(1); + uint32_t delay = SDL_GetTicks()-start; + if (delay > min_delay) { + min_delay = delay; + } + } + if (!min_delay) { + min_delay = 1; + } + printf("minimum delay: %d\n", min_delay); + + frame_delay = 1000/fps; + + audio_mutex = SDL_CreateMutex(); + psg_cond = SDL_CreateCond(); + ym_cond = SDL_CreateCond(); + audio_ready = SDL_CreateCond(); + + SDL_AudioSpec desired, actual; char * rate_str = tern_find_ptr(config, "audiorate"); int rate = rate_str ? atoi(rate_str) : 0; if (!rate) { rate = 48000; } desired.freq = rate; - desired.format = AUDIO_S16SYS; - desired.channels = 2; + desired.format = AUDIO_S16SYS; + desired.channels = 2; char * samples_str = tern_find_ptr(config, "audiobuffer"); int samples = samples_str ? atoi(samples_str) : 0; if (!samples) { @@ -158,29 +296,62 @@ } printf("config says: %d\n", samples); desired.samples = samples*2; - desired.callback = audio_callback; - desired.userdata = NULL; - - if (SDL_OpenAudio(&desired, &actual) < 0) { - fprintf(stderr, "Unable to open SDL audio: %s\n", SDL_GetError()); - exit(1); - } - buffer_samples = actual.samples; - sample_rate = actual.freq; - printf("Initialized audio at frequency %d with a %d sample buffer\n", actual.freq, actual.samples); - SDL_PauseAudio(0); - num_joysticks = SDL_NumJoysticks(); - if (num_joysticks > MAX_JOYSTICKS) { - num_joysticks = MAX_JOYSTICKS; - } - for (int i = 0; i < num_joysticks; i++) { - printf("Joystick %d: %s\n", i, SDL_JoystickName(i)); - SDL_Joystick * joy = joysticks[i] = SDL_JoystickOpen(i); - if (joy) { - printf("\tNum Axes: %d\n\tNum Buttons: %d\n\tNum Hats: %d\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy)); - } - } - SDL_JoystickEventState(SDL_ENABLE); + desired.callback = audio_callback; + desired.userdata = NULL; + + if (SDL_OpenAudio(&desired, &actual) < 0) { + fprintf(stderr, "Unable to open SDL audio: %s\n", SDL_GetError()); + exit(1); + } + buffer_samples = actual.samples; + sample_rate = actual.freq; + printf("Initialized audio at frequency %d with a %d sample buffer\n", actual.freq, actual.samples); + SDL_PauseAudio(0); + num_joysticks = SDL_NumJoysticks(); + if (num_joysticks > MAX_JOYSTICKS) { + num_joysticks = MAX_JOYSTICKS; + } + for (int i = 0; i < num_joysticks; i++) { + printf("Joystick %d: %s\n", i, SDL_JoystickName(i)); + SDL_Joystick * joy = joysticks[i] = SDL_JoystickOpen(i); + if (joy) { + printf("\tNum Axes: %d\n\tNum Buttons: %d\n\tNum Hats: %d\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy)); + } + } + SDL_JoystickEventState(SDL_ENABLE); +} + +void render_context_gl(vdp_context * context) +{ + glBindTexture(GL_TEXTURE_2D, textures[context->framebuf == context->oddbuf ? 0 : 1]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 240, GL_BGRA, GL_UNSIGNED_BYTE, context->framebuf);; + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(program); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textures[0]); + glUniform1i(un_textures[0], 0); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, (context->regs[REG_MODE_4] & BIT_INTERLACE) ? textures[1] : textures[2]); + glUniform1i(un_textures[1], 1); + + glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); + glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); + glEnableVertexAttribArray(at_pos); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0); + + glDisableVertexAttribArray(at_pos); + + SDL_GL_SwapBuffers(); + if (context->regs[REG_MODE_4] & BIT_INTERLACE) + { + context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; + } } uint32_t blankbuf[320*240]; @@ -188,65 +359,70 @@ void render_context(vdp_context * context) { uint16_t *buf_16; - uint32_t *buf_32; + uint32_t *buf_32; uint8_t b,g,r; last_frame = SDL_GetTicks(); + if (render_gl) + { + render_context_gl(context); + return; + } if (SDL_MUSTLOCK(screen)) { if (SDL_LockSurface(screen) < 0) { return; } - } - uint16_t repeat_x = screen->clip_rect.w / 320; - uint16_t repeat_y = screen->clip_rect.h / 240; - if (repeat_x > repeat_y) { - repeat_x = repeat_y; - } else { - repeat_y = repeat_x; - } - int othermask = repeat_y >> 1; - - if (screen->format->BytesPerPixel == 2) { - uint16_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint16_t *)blankbuf; - uint16_t * oddbuf = context->oddbuf; - buf_16 = (uint16_t *)screen->pixels; - for (int y = 0; y < 240; y++) { - for (int i = 0; i < repeat_y; i++,buf_16 += screen->pitch/2) { - uint16_t *line = buf_16; - uint16_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; - for (int x = 0; x < 320; x++) { - uint16_t color = *(src_line++); - for (int j = 0; j < repeat_x; j++) { - *(line++) = color; - } - } - } - } - } else { - uint32_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint32_t *)blankbuf; - uint32_t * oddbuf = context->oddbuf; - buf_32 = (uint32_t *)screen->pixels; - for (int y = 0; y < 240; y++) { - for (int i = 0; i < repeat_y; i++,buf_32 += screen->pitch/4) { - uint32_t *line = buf_32; - uint32_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; - for (int x = 0; x < 320; x++) { - uint32_t color = *(src_line++); - for (int j = 0; j < repeat_x; j++) { - *(line++) = color; - } - } - } - } - } - if ( SDL_MUSTLOCK(screen) ) { - SDL_UnlockSurface(screen); - } + } + uint16_t repeat_x = screen->clip_rect.w / 320; + uint16_t repeat_y = screen->clip_rect.h / 240; + if (repeat_x > repeat_y) { + repeat_x = repeat_y; + } else { + repeat_y = repeat_x; + } + int othermask = repeat_y >> 1; + + if (screen->format->BytesPerPixel == 2) { + uint16_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint16_t *)blankbuf; + uint16_t * oddbuf = context->oddbuf; + buf_16 = (uint16_t *)screen->pixels; + for (int y = 0; y < 240; y++) { + for (int i = 0; i < repeat_y; i++,buf_16 += screen->pitch/2) { + uint16_t *line = buf_16; + uint16_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; + for (int x = 0; x < 320; x++) { + uint16_t color = *(src_line++); + for (int j = 0; j < repeat_x; j++) { + *(line++) = color; + } + } + } + } + } else { + uint32_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint32_t *)blankbuf; + uint32_t * oddbuf = context->oddbuf; + buf_32 = (uint32_t *)screen->pixels; + for (int y = 0; y < 240; y++) { + for (int i = 0; i < repeat_y; i++,buf_32 += screen->pitch/4) { + uint32_t *line = buf_32; + uint32_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; + for (int x = 0; x < 320; x++) { + uint32_t color = *(src_line++); + for (int j = 0; j < repeat_x; j++) { + *(line++) = color; + } + } + } + } + } + if ( SDL_MUSTLOCK(screen) ) { + SDL_UnlockSurface(screen); + } //SDL_UpdateRect(screen, 0, 0, screen->clip_rect.w, screen->clip_rect.h); SDL_Flip(screen); - if (context->regs[REG_MODE_4] & BIT_INTERLACE) - { - context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; - } + if (context->regs[REG_MODE_4] & BIT_INTERLACE) + { + context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; + } } int render_joystick_num_buttons(int joystick) diff -r db5880d8ea03 -r dffc07104b09 vdp.c --- a/vdp.c Thu Oct 03 21:22:05 2013 -0700 +++ b/vdp.c Sun Oct 27 22:08:02 2013 -0700 @@ -50,10 +50,13 @@ memset(context, 0, sizeof(*context)); context->vdpmem = malloc(VRAM_SIZE); memset(context->vdpmem, 0, VRAM_SIZE); - context->oddbuf = context->framebuf = malloc(FRAMEBUF_ENTRIES * (render_depth() / 8)); + /*context->oddbuf = context->framebuf = malloc(FRAMEBUF_ENTRIES * (render_depth() / 8)); memset(context->framebuf, 0, FRAMEBUF_ENTRIES * (render_depth() / 8)); context->evenbuf = malloc(FRAMEBUF_ENTRIES * (render_depth() / 8)); memset(context->evenbuf, 0, FRAMEBUF_ENTRIES * (render_depth() / 8)); + */ + render_alloc_surfaces(context); + context->framebuf = context->oddbuf; context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); context->tmp_buf_a = context->linebuf + LINEBUF_SIZE;