comparison render_sdl.c @ 798:062a2199daf6

Use SDL2 renderer as a fallback
author =?UTF-8?q?Higor=20Eur=C3=ADpedes?= <heuripedes@gmail.com>
date Sun, 26 Jul 2015 13:08:22 -0700
parents 65181c3ee560
children 0b692b5d154b
comparison
equal deleted inserted replaced
797:65181c3ee560 798:062a2199daf6
10 #include "render.h" 10 #include "render.h"
11 #include "blastem.h" 11 #include "blastem.h"
12 #include "io.h" 12 #include "io.h"
13 #include "util.h" 13 #include "util.h"
14 14
15 #ifndef DISABLE_OPENGL
15 #include <GL/glew.h> 16 #include <GL/glew.h>
17 #endif
16 18
17 SDL_Window *main_window; 19 SDL_Window *main_window;
18 #ifdef DISABLE_OPENGL
19 SDL_Renderer *main_renderer; 20 SDL_Renderer *main_renderer;
20 SDL_Texture *main_texture; 21 SDL_Texture *main_texture;
21 SDL_Rect main_clip; 22 SDL_Rect main_clip;
22 #else
23 SDL_GLContext *main_context; 23 SDL_GLContext *main_context;
24 #endif
25 24
26 uint8_t render_dbg = 0; 25 uint8_t render_dbg = 0;
27 uint8_t debug_pal = 0; 26 uint8_t debug_pal = 0;
27 uint8_t render_gl = 1;
28 28
29 uint32_t last_frame = 0; 29 uint32_t last_frame = 0;
30 30
31 uint32_t min_delay; 31 uint32_t min_delay;
32 uint32_t frame_delay = 1000/60; 32 uint32_t frame_delay = 1000/60;
99 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) 99 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b)
100 { 100 {
101 return 255 << 24 | r << 16 | g << 8 | b; 101 return 255 << 24 | r << 16 | g << 8 | b;
102 } 102 }
103 103
104 #ifndef DISABLE_OPENGL
104 GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, at_pos; 105 GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, at_pos;
105 106
106 GLfloat vertex_data[] = { 107 GLfloat vertex_data[] = {
107 -1.0f, -1.0f, 108 -1.0f, -1.0f,
108 1.0f, -1.0f, 109 1.0f, -1.0f,
152 glDeleteShader(ret); 153 glDeleteShader(ret);
153 return 0; 154 return 0;
154 } 155 }
155 return ret; 156 return ret;
156 } 157 }
158 #endif
157 159
158 void render_alloc_surfaces(vdp_context * context) 160 void render_alloc_surfaces(vdp_context * context)
159 { 161 {
160 context->oddbuf = context->framebuf = malloc(512 * 256 * 4 * 2); 162 context->oddbuf = context->framebuf = malloc(512 * 256 * 4 * 2);
161 memset(context->oddbuf, 0, 512 * 256 * 4 * 2); 163 memset(context->oddbuf, 0, 512 * 256 * 4 * 2);
162 context->evenbuf = ((char *)context->oddbuf) + 512 * 256 * 4; 164 context->evenbuf = ((char *)context->oddbuf) + 512 * 256 * 4;
163 165
164 #ifdef DISABLE_OPENGL 166 #ifndef DISABLE_OPENGL
167 if (render_gl) {
168 glGenTextures(3, textures);
169 for (int i = 0; i < 3; i++)
170 {
171 glBindTexture(GL_TEXTURE_2D, textures[i]);
172 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
173 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
175 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
176 if (i < 2) {
177 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, i ? context->evenbuf : context->oddbuf);
178 } else {
179 uint32_t blank = 255 << 24;
180 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank);
181 }
182 }
183 glGenBuffers(2, buffers);
184 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
185 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
186 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
187 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW);
188 tern_val def = {.ptrval = "default.v.glsl"};
189 vshader = load_shader(tern_find_path_default(config, "video\0vertex_shader\0", def).ptrval, GL_VERTEX_SHADER);
190 def.ptrval = "default.f.glsl";
191 fshader = load_shader(tern_find_path_default(config, "video\0fragment_shader\0", def).ptrval, GL_FRAGMENT_SHADER);
192 program = glCreateProgram();
193 glAttachShader(program, vshader);
194 glAttachShader(program, fshader);
195 glLinkProgram(program);
196 GLint link_status;
197 glGetProgramiv(program, GL_LINK_STATUS, &link_status);
198 if (!link_status) {
199 fputs("Failed to link shader program\n", stderr);
200 exit(1);
201 }
202 un_textures[0] = glGetUniformLocation(program, "textures[0]");
203 un_textures[1] = glGetUniformLocation(program, "textures[1]");
204 un_width = glGetUniformLocation(program, "width");
205 at_pos = glGetAttribLocation(program, "pos");
206 } else {
207 #endif
165 /* height=480 to fit interlaced output */ 208 /* height=480 to fit interlaced output */
166 main_texture = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 480); 209 main_texture = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 480);
167 #else 210 #ifndef DISABLE_OPENGL
168 glGenTextures(3, textures); 211 }
169 for (int i = 0; i < 3; i++)
170 {
171 glBindTexture(GL_TEXTURE_2D, textures[i]);
172 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
173 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
175 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
176 if (i < 2) {
177 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, i ? context->evenbuf : context->oddbuf);
178 } else {
179 uint32_t blank = 255 << 24;
180 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank);
181 }
182 }
183 glGenBuffers(2, buffers);
184 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
185 glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW);
186 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
187 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW);
188 tern_val def = {.ptrval = "default.v.glsl"};
189 vshader = load_shader(tern_find_path_default(config, "video\0vertex_shader\0", def).ptrval, GL_VERTEX_SHADER);
190 def.ptrval = "default.f.glsl";
191 fshader = load_shader(tern_find_path_default(config, "video\0fragment_shader\0", def).ptrval, GL_FRAGMENT_SHADER);
192 program = glCreateProgram();
193 glAttachShader(program, vshader);
194 glAttachShader(program, fshader);
195 glLinkProgram(program);
196 GLint link_status;
197 glGetProgramiv(program, GL_LINK_STATUS, &link_status);
198 if (!link_status) {
199 fputs("Failed to link shader program\n", stderr);
200 exit(1);
201 }
202 un_textures[0] = glGetUniformLocation(program, "textures[0]");
203 un_textures[1] = glGetUniformLocation(program, "textures[1]");
204 un_width = glGetUniformLocation(program, "width");
205 at_pos = glGetAttribLocation(program, "pos");
206 #endif 212 #endif
207 } 213 }
208 214
209 char * caption = NULL; 215 char * caption = NULL;
210 216
236 //but that doesn't seem to work right when using OpenGL, at least on Linux anyway 242 //but that doesn't seem to work right when using OpenGL, at least on Linux anyway
237 width = mode.w; 243 width = mode.w;
238 height = mode.h; 244 height = mode.h;
239 } 245 }
240 246
241 #ifdef DISABLE_OPENGL 247 render_gl = 0;
242 SDL_CreateWindowAndRenderer(width, height, flags, &main_window, &main_renderer); 248
243 249 #ifndef DISABLE_OPENGL
244 if (!main_window || !main_renderer) {
245 fprintf(stderr, "unable to create SDL window: %s\n", SDL_GetError());
246 SDL_Quit();
247 exit(1);
248 }
249 main_clip.x = main_clip.y = 0;
250 main_clip.w = width;
251 main_clip.h = height;
252 #else
253 flags |= SDL_WINDOW_OPENGL; 250 flags |= SDL_WINDOW_OPENGL;
254 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); 251 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
255 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); 252 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
256 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); 253 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
257 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); 254 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
264 } 261 }
265 main_context = SDL_GL_CreateContext(main_window); 262 main_context = SDL_GL_CreateContext(main_window);
266 GLenum res = glewInit(); 263 GLenum res = glewInit();
267 if (res != GLEW_OK) { 264 if (res != GLEW_OK) {
268 fprintf(stderr, "Initialization of GLEW failed with code %d\n", res); 265 fprintf(stderr, "Initialization of GLEW failed with code %d\n", res);
269 SDL_Quit(); 266 SDL_DestroyWindow(main_window);
270 exit(1); 267 }
271 } 268
272 if (!GLEW_VERSION_2_0) { 269 if (GLEW_VERSION_2_0) {
273 fputs("BlastEm requires at least OpenGL 2.0, but it is unavailable\n", stderr); 270 render_gl = 1;
274 SDL_Quit(); 271 }
275 exit(1); 272 else {
276 } 273 SDL_DestroyWindow(main_window);
277 #endif 274 fputs("OpenGL 2.0 is unavailable, falling back to SDL2 renderer\n", stderr);
275 #endif
276 SDL_CreateWindowAndRenderer(width, height, flags, &main_window, &main_renderer);
277
278 if (!main_window || !main_renderer) {
279 fprintf(stderr, "unable to create SDL window: %s\n", SDL_GetError());
280 SDL_Quit();
281 exit(1);
282 }
283 main_clip.x = main_clip.y = 0;
284 main_clip.w = width;
285 main_clip.h = height;
286 #ifndef DISABLE_OPENGL
287 }
288 #endif
289
278 SDL_GetWindowSize(main_window, &width, &height); 290 SDL_GetWindowSize(main_window, &width, &height);
279 printf("Window created with size: %d x %d\n", width, height); 291 printf("Window created with size: %d x %d\n", width, height);
280 float src_aspect = 4.0/3.0; 292 float src_aspect = 4.0/3.0;
281 float aspect = (float)width / height; 293 float aspect = (float)width / height;
282 tern_val def = {.ptrval = "normal"}; 294 tern_val def = {.ptrval = "normal"};
283 int stretch = fabs(aspect - src_aspect) > 0.01 && !strcmp(tern_find_path_default(config, "video\0aspect\0", def).ptrval, "stretch"); 295 int stretch = fabs(aspect - src_aspect) > 0.01 && !strcmp(tern_find_path_default(config, "video\0aspect\0", def).ptrval, "stretch");
284 296
285 #ifdef DISABLE_OPENGL
286 if (!stretch) { 297 if (!stretch) {
287 float scale_x = (float)width / 320.0; 298 #ifndef DISABLE_OPENGL
288 float scale_y = (float)height / 240.0; 299 if (render_gl) {
289 float scale = scale_x > scale_y ? scale_y : scale_x; 300 for (int i = 0; i < 4; i++)
290 main_clip.w = 320.0 * scale; 301 {
291 main_clip.h = 240.0 * scale; 302 if (aspect > src_aspect) {
292 main_clip.x = (width - main_clip.w) / 2; 303 vertex_data[i*2] *= src_aspect/aspect;
293 main_clip.y = (height - main_clip.h) / 2; 304 } else {
294 } 305 vertex_data[i*2+1] *= aspect/src_aspect;
295 #else 306 }
296 if (!stretch) { 307 }
297 for (int i = 0; i < 4; i++) 308 } else {
298 { 309 #endif
299 if (aspect > src_aspect) { 310 float scale_x = (float)width / 320.0;
300 vertex_data[i*2] *= src_aspect/aspect; 311 float scale_y = (float)height / 240.0;
301 } else { 312 float scale = scale_x > scale_y ? scale_y : scale_x;
302 vertex_data[i*2+1] *= aspect/src_aspect; 313 main_clip.w = 320.0 * scale;
303 } 314 main_clip.h = 240.0 * scale;
304 } 315 main_clip.x = (width - main_clip.w) / 2;
305 } 316 main_clip.y = (height - main_clip.h) / 2;
306 #endif 317 #ifndef DISABLE_OPENGL
318 }
319 #endif
320 }
321
307 caption = title; 322 caption = title;
308 min_delay = 0; 323 min_delay = 0;
309 for (int i = 0; i < 100; i++) { 324 for (int i = 0; i < 100; i++) {
310 uint32_t start = SDL_GetTicks(); 325 uint32_t start = SDL_GetTicks();
311 SDL_Delay(1); 326 SDL_Delay(1);
374 { 389 {
375 int width = context->regs[REG_MODE_4] & BIT_H40 ? 320.0f : 256.0f; 390 int width = context->regs[REG_MODE_4] & BIT_H40 ? 320.0f : 256.0f;
376 int height = 240; 391 int height = 240;
377 392
378 last_frame = SDL_GetTicks(); 393 last_frame = SDL_GetTicks();
379 #ifdef DISABLE_OPENGL 394 #ifndef DISABLE_OPENGL
380 SDL_Rect area; 395 if (render_gl) {
381 396 glBindTexture(GL_TEXTURE_2D, textures[context->framebuf == context->oddbuf ? 0 : 1]);
382 area.x = area.y = 0; 397 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 240, GL_BGRA, GL_UNSIGNED_BYTE, context->framebuf);;
383 area.w = width; 398
384 area.h = height; 399 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
385 400 glClear(GL_COLOR_BUFFER_BIT);
386 if (context->regs[REG_MODE_4] & BIT_INTERLACE) 401
387 { 402 glUseProgram(program);
388 unsigned skip; 403 glActiveTexture(GL_TEXTURE0);
389 uint32_t *src = (uint32_t*)context->framebuf; 404 glBindTexture(GL_TEXTURE_2D, textures[0]);
390 uint8_t *dst; 405 glUniform1i(un_textures[0], 0);
391 int i; 406
392 407 glActiveTexture(GL_TEXTURE1);
393 area.h *= 2; 408 glBindTexture(GL_TEXTURE_2D, (context->regs[REG_MODE_4] & BIT_INTERLACE) ? textures[1] : textures[2]);
394 409 glUniform1i(un_textures[1], 1);
395 SDL_LockTexture(main_texture, &area, (void**)&dst, &skip); 410
396 411 glUniform1f(un_width, width);
397 if (context->framebuf == context->evenbuf) 412
398 dst += skip; 413 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
399 414 glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0);
400 skip *= 2; 415 glEnableVertexAttribArray(at_pos);
401 416
402 for (i = 0; i < 240; ++i) 417 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
403 { 418 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0);
404 memcpy(dst, src, width*sizeof(uint32_t)); 419
405 src += 320; 420 glDisableVertexAttribArray(at_pos);
406 dst += skip; 421
407 } 422 SDL_GL_SwapWindow(main_window);
408 423 } else {
409 SDL_UnlockTexture(main_texture); 424 #endif
410 } 425 SDL_Rect area;
411 else /* possibly faster path for non-interlaced output */ 426
412 SDL_UpdateTexture(main_texture, &area, context->framebuf, 320*sizeof(uint32_t)); 427 area.x = area.y = 0;
413 428 area.w = width;
414 SDL_RenderClear(main_renderer); 429 area.h = height;
415 SDL_RenderCopy(main_renderer, main_texture, &area, &main_clip); 430
416 SDL_RenderPresent(main_renderer); 431 if (context->regs[REG_MODE_4] & BIT_INTERLACE) {
417 #else 432 unsigned skip;
418 glBindTexture(GL_TEXTURE_2D, textures[context->framebuf == context->oddbuf ? 0 : 1]); 433 uint32_t *src = (uint32_t*)context->framebuf;
419 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 240, GL_BGRA, GL_UNSIGNED_BYTE, context->framebuf);; 434 uint8_t *dst;
420 435 int i;
421 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 436
422 glClear(GL_COLOR_BUFFER_BIT); 437 area.h *= 2;
423 438
424 glUseProgram(program); 439 SDL_LockTexture(main_texture, &area, (void**)&dst, &skip);
425 glActiveTexture(GL_TEXTURE0); 440
426 glBindTexture(GL_TEXTURE_2D, textures[0]); 441 if (context->framebuf == context->evenbuf)
427 glUniform1i(un_textures[0], 0); 442 dst += skip;
428 443
429 glActiveTexture(GL_TEXTURE1); 444 skip *= 2;
430 glBindTexture(GL_TEXTURE_2D, (context->regs[REG_MODE_4] & BIT_INTERLACE) ? textures[1] : textures[2]); 445
431 glUniform1i(un_textures[1], 1); 446 for (i = 0; i < 240; ++i) {
432 447 memcpy(dst, src, width*sizeof(uint32_t));
433 glUniform1f(un_width, width); 448 src += 320;
434 449 dst += skip;
435 glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); 450 }
436 glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); 451
437 glEnableVertexAttribArray(at_pos); 452 SDL_UnlockTexture(main_texture);
438 453 }
439 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); 454 else /* possibly faster path for non-interlaced output */
440 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0); 455 SDL_UpdateTexture(main_texture, &area, context->framebuf, 320*sizeof(uint32_t));
441 456
442 glDisableVertexAttribArray(at_pos); 457 SDL_RenderClear(main_renderer);
443 458 SDL_RenderCopy(main_renderer, main_texture, &area, &main_clip);
444 SDL_GL_SwapWindow(main_window); 459 SDL_RenderPresent(main_renderer);
445 #endif 460 #ifndef DISABLE_OPENGL
446 if (context->regs[REG_MODE_4] & BIT_INTERLACE) 461 }
447 { 462 #endif
463
464 if (context->regs[REG_MODE_4] & BIT_INTERLACE) {
448 context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; 465 context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf;
449 } 466 }
450 } 467 }
451 468
452 int render_joystick_num_buttons(int joystick) 469 int render_joystick_num_buttons(int joystick)