1 // license:BSD-3-Clause
2 // copyright-holders:Olivier Galibert, R. Belmont
3 //============================================================
4 //
5 // drawogl.c - SDL software and OpenGL implementation
6 //
7 // SDLMAME by Olivier Galibert and R. Belmont
8 //
9 // Note: D3D9 goes to a lot of trouble to fiddle with MODULATE
10 // mode on textures. That is the default in OpenGL so we
11 // don't have to touch it.
12 //
13 //============================================================
14
15 // standard C headers
16 #include <cmath>
17 #include <cstdio>
18
19 // MAME headers
20 #include "osdcomm.h"
21 #include "emu.h"
22 #include "emuopts.h"
23
24 #ifdef OSD_MAC
25 #define GL_SILENCE_DEPRECATION (1)
26 #endif
27
28 #if !defined(OSD_WINDOWS) && !defined(OSD_MAC)
29 // standard SDL headers
30 #define TOBEMIGRATED 1
31 #include <SDL2/SDL.h>
32 #endif
33
34 #include "modules/lib/osdlib.h"
35 #include "modules/lib/osdobj_common.h"
36
37 // OpenGL headers
38 #include "modules/opengl/osd_opengl.h"
39
40 #include "modules/opengl/gl_shader_tool.h"
41 #include "modules/opengl/gl_shader_mgr.h"
42
43 #if defined(SDLMAME_MACOSX) || defined(OSD_MAC)
44 #include <cstring>
45 #include <cstdio>
46 #include <sys/types.h>
47 #include <sys/sysctl.h>
48
49 #ifndef APIENTRY
50 #define APIENTRY
51 #endif
52 #ifndef APIENTRYP
53 #define APIENTRYP APIENTRY *
54 #endif
55
56 typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
57 typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum, GLuint);
58 typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum, GLsizeiptr, const GLvoid *, GLenum);
59 typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum, GLintptr, GLsizeiptr, const GLvoid *);
60 typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum, GLenum);
61 typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum);
62 typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei, const GLuint *);
63 typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
64 typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFEREXTPROC) (GLuint framebuffer);
65 typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum m_target, GLuint framebuffer);
66 typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);
67 typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);
68 typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum m_target);
69 typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum m_target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
70 typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);
71 typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum m_target, GLuint renderbuffer);
72 typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum m_target, GLenum internalformat, GLsizei width, GLsizei height);
73 typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum m_target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
74 typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);
75 #endif
76
77 // make sure the extensions compile OK everywhere
78 #ifndef GL_TEXTURE_STORAGE_HINT_APPLE
79 #define GL_TEXTURE_STORAGE_HINT_APPLE 0x85bc
80 #endif
81
82 #ifndef GL_STORAGE_CACHED_APPLE
83 #define GL_STORAGE_CACHED_APPLE 0x85be
84 #endif
85
86 #ifndef GL_UNPACK_CLIENT_STORAGE_APPLE
87 #define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85b2
88 #endif
89
90 #ifndef GL_TEXTURE_RECTANGLE_ARB
91 #define GL_TEXTURE_RECTANGLE_ARB 0x84F5
92 #endif
93
94 #ifndef GL_PIXEL_UNPACK_BUFFER_ARB
95 #define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC
96 #endif
97
98 #ifndef GL_STREAM_DRAW
99 #define GL_STREAM_DRAW 0x88E0
100 #endif
101
102 #ifndef GL_WRITE_ONLY
103 #define GL_WRITE_ONLY 0x88B9
104 #endif
105
106 #ifndef GL_ARRAY_BUFFER_ARB
107 #define GL_ARRAY_BUFFER_ARB 0x8892
108 #endif
109
110 #ifndef GL_PIXEL_UNPACK_BUFFER_ARB
111 #define GL_PIXEL_UNPACK_BUFFER_ARB 0x88EC
112 #endif
113
114 #ifndef GL_FRAMEBUFFER_EXT
115 #define GL_FRAMEBUFFER_EXT 0x8D40
116 #define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5
117 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT 0x8CD6
118 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT 0x8CD7
119 #define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8
120 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT 0x8CD9
121 #define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT 0x8CDA
122 #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT 0x8CDB
123 #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT 0x8CDC
124 #define GL_FRAMEBUFFER_UNSUPPORTED_EXT 0x8CDD
125 #define GL_RENDERBUFFER_EXT 0x8D41
126 #define GL_DEPTH_COMPONENT16 0x81A5
127 #define GL_DEPTH_COMPONENT24 0x81A6
128 #define GL_DEPTH_COMPONENT32 0x81A7
129 #endif
130
131 #include "drawogl.h"
132
133 //============================================================
134 // DEBUGGING
135 //============================================================
136
137 #define DEBUG_MODE_SCORES 0
138 #define USE_WIN32_STYLE_LINES 0 // use the same method baseline does - yields somewhat nicer vectors but a little buggy
139
140 //============================================================
141 // CONSTANTS
142 //============================================================
143
144 enum
145 {
146 TEXTURE_TYPE_NONE,
147 TEXTURE_TYPE_PLAIN,
148 TEXTURE_TYPE_DYNAMIC,
149 TEXTURE_TYPE_SHADER,
150 TEXTURE_TYPE_SURFACE
151 };
152
153
154 //============================================================
155 // MACROS
156 //============================================================
157
158 // texture formats
159 // This used to be an enum, but these are now defines so we can use them as
160 // preprocessor conditionals
161 #define SDL_TEXFORMAT_ARGB32 (0) // non-16-bit textures or specials
162 #define SDL_TEXFORMAT_RGB32 (1)
163 #define SDL_TEXFORMAT_RGB32_PALETTED (2)
164 #define SDL_TEXFORMAT_YUY16 (3)
165 #define SDL_TEXFORMAT_YUY16_PALETTED (4)
166 #define SDL_TEXFORMAT_PALETTE16 (5)
167 #define SDL_TEXFORMAT_RGB15 (6)
168 #define SDL_TEXFORMAT_RGB15_PALETTED (7)
169 #define SDL_TEXFORMAT_PALETTE16A (8)
170 #if 0
171 // special texture formats for 16bpp texture destination support, do not use
172 // to address the tex properties / tex functions arrays!
173 #define SDL_TEXFORMAT_PALETTE16_ARGB1555 (16)
174 #define SDL_TEXFORMAT_RGB15_ARGB1555 (17)
175 #define SDL_TEXFORMAT_RGB15_PALETTED_ARGB1555 (18)
176 #endif
177
178 #define FSWAP(var1, var2) do { float temp = var1; var1 = var2; var2 = temp; } while (0)
179 #define GL_NO_PRIMITIVE -1
180
181 /* line_aa_step is used for drawing antialiased lines */
182 struct line_aa_step
183 {
184 float xoffs, yoffs; // X/Y deltas
185 float weight; // weight contribution
186 };
187
188 #if 0
189 static const line_aa_step line_aa_1step[] =
190 {
191 { 0.00f, 0.00f, 1.00f },
192 { 0 }
193 };
194
195 static const line_aa_step line_aa_4step[] =
196 {
197 { -0.25f, 0.00f, 0.25f },
198 { 0.25f, 0.00f, 0.25f },
199 { 0.00f, -0.25f, 0.25f },
200 { 0.00f, 0.25f, 0.25f },
201 { 0 }
202 };
203 #endif
204
205 //============================================================
206 // INLINES
207 //============================================================
208
texture_compute_hash(const render_texinfo * texture,uint32_t flags)209 HashT renderer_ogl::texture_compute_hash(const render_texinfo *texture, uint32_t flags)
210 {
211 HashT h = (HashT)texture->base ^ (flags & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK));
212 //printf("hash %d\n", (int) h % HASH_SIZE);
213 return (h >> 8) % HASH_SIZE;
214 }
215
set_blendmode(int blendmode)216 void renderer_ogl::set_blendmode(int blendmode)
217 {
218 // try to minimize texture state changes
219 if (blendmode != m_last_blendmode)
220 {
221 switch (blendmode)
222 {
223 case BLENDMODE_NONE:
224 glDisable(GL_BLEND);
225 break;
226 case BLENDMODE_ALPHA:
227 glEnable(GL_BLEND);
228 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
229 break;
230 case BLENDMODE_RGB_MULTIPLY:
231 glEnable(GL_BLEND);
232 glBlendFunc(GL_DST_COLOR, GL_ZERO);
233 break;
234 case BLENDMODE_ADD:
235 glEnable(GL_BLEND);
236 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
237 break;
238 }
239
240 m_last_blendmode = blendmode;
241 }
242 }
243
244 //============================================================
245 // STATIC VARIABLES
246 //============================================================
247
248 // OGL 1.3
249 #if defined(GL_ARB_multitexture) && !defined(OSD_MAC)
250 static PFNGLACTIVETEXTUREARBPROC pfn_glActiveTexture = nullptr;
251 #else
252 static PFNGLACTIVETEXTUREPROC pfn_glActiveTexture = nullptr;
253 #endif
254
255 // VBO
256 static PFNGLGENBUFFERSPROC pfn_glGenBuffers = nullptr;
257 static PFNGLDELETEBUFFERSPROC pfn_glDeleteBuffers = nullptr;
258 static PFNGLBINDBUFFERPROC pfn_glBindBuffer = nullptr;
259 static PFNGLBUFFERDATAPROC pfn_glBufferData = nullptr;
260 static PFNGLBUFFERSUBDATAPROC pfn_glBufferSubData = nullptr;
261
262 // PBO
263 static PFNGLMAPBUFFERPROC pfn_glMapBuffer = nullptr;
264 static PFNGLUNMAPBUFFERPROC pfn_glUnmapBuffer = nullptr;
265
266 // FBO
267 static PFNGLISFRAMEBUFFEREXTPROC pfn_glIsFramebuffer = nullptr;
268 static PFNGLBINDFRAMEBUFFEREXTPROC pfn_glBindFramebuffer = nullptr;
269 static PFNGLDELETEFRAMEBUFFERSEXTPROC pfn_glDeleteFramebuffers = nullptr;
270 static PFNGLGENFRAMEBUFFERSEXTPROC pfn_glGenFramebuffers = nullptr;
271 static PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC pfn_glCheckFramebufferStatus = nullptr;
272 static PFNGLFRAMEBUFFERTEXTURE2DEXTPROC pfn_glFramebufferTexture2D = nullptr;
273
274 static int glsl_shader_feature = GLSL_SHADER_FEAT_PLAIN;
275
276 //============================================================
277 // Textures
278 //============================================================
279
280 static void texture_set_data(ogl_texture_info *texture, const render_texinfo *texsource, uint32_t flags);
281
282 //============================================================
283 // Static Variables
284 //============================================================
285
286 bool renderer_ogl::s_shown_video_info = false;
287 bool renderer_ogl::s_dll_loaded = false;
288
init(running_machine & machine)289 void renderer_ogl::init(running_machine &machine)
290 {
291 s_dll_loaded = false;
292
293 load_gl_lib(machine);
294 #if defined(OSD_WINDOWS)
295 osd_printf_verbose("Using Windows OpenGL driver\n");
296 #else
297 osd_printf_verbose("Using SDL multi-window OpenGL driver (SDL 2.0+)\n");
298 #endif
299 }
300
301 //============================================================
302 // CONSTRUCTOR & DESTRUCTOR
303 //============================================================
304
~renderer_ogl()305 renderer_ogl::~renderer_ogl()
306 {
307 // free the memory in the window
308 destroy_all_textures();
309
310 delete m_gl_context;
311 m_gl_context = nullptr;
312 }
313
exit()314 void renderer_ogl::exit()
315 {
316 for (int i = 0; i < video_config.glsl_shader_mamebm_num; i++)
317 {
318 if (nullptr != video_config.glsl_shader_mamebm[i])
319 {
320 free(video_config.glsl_shader_mamebm[i]);
321 video_config.glsl_shader_mamebm[i] = nullptr;
322 }
323 }
324 for (int i =0; i < video_config.glsl_shader_scrn_num; i++)
325 {
326 if (nullptr != video_config.glsl_shader_scrn[i])
327 {
328 free(video_config.glsl_shader_scrn[i]);
329 video_config.glsl_shader_scrn[i] = nullptr;
330 }
331 }
332 }
333
334 //============================================================
335 // Load the OGL function addresses
336 //============================================================
337
loadgl_functions(osd_gl_context * context)338 static void loadgl_functions(osd_gl_context *context)
339 {
340 #ifdef USE_DISPATCH_GL
341
342 int err_count = 0;
343
344 /* the following is tricky ... #func will be expanded to glBegin
345 * while func will be expanded to disp_p->glBegin
346 */
347
348 #define OSD_GL(ret,func,params) \
349 if (!( func = (ret (APIENTRY *)params) context->getProcAddress( #func ) )) \
350 { err_count++; osd_printf_error("GL function %s not found!\n", #func ); }
351
352 #define OSD_GL_UNUSED(ret,func,params)
353
354 #define GET_GLFUNC 1
355 #include "modules/opengl/osd_opengl.h"
356 #undef GET_GLFUNC
357
358 if (err_count)
359 fatalerror("Error loading GL library functions, giving up\n");
360
361 #endif
362 }
363
364 //============================================================
365 // Load GL library
366 //============================================================
367
368 #ifdef USE_DISPATCH_GL
369 osd_gl_dispatch *gl_dispatch = nullptr;
370 #endif
371
load_gl_lib(running_machine & machine)372 void renderer_ogl::load_gl_lib(running_machine &machine)
373 {
374 if (!s_dll_loaded)
375 {
376 #ifndef OSD_WINDOWS
377 #ifdef USE_DISPATCH_GL
378 /*
379 * directfb and and x11 use this env var
380 * SDL_VIDEO_GL_DRIVER
381 */
382 const char *stemp;
383
384 stemp = downcast<sdl_options &>(machine.options()).gl_lib();
385 if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) == 0)
386 stemp = nullptr;
387
388 if (SDL_GL_LoadLibrary(stemp) != 0) // Load library (default for e==nullptr
389 {
390 fatalerror("Unable to load opengl library: %s\n", stemp ? stemp : "<default>");
391 }
392 osd_printf_verbose("Loaded opengl shared library: %s\n", stemp ? stemp : "<default>");
393 /* FIXME: must be freed as well */
394 #endif
395 #endif
396 #ifdef USE_DISPATCH_GL
397 gl_dispatch = new osd_gl_dispatch;
398 #endif
399 s_dll_loaded = true;
400 }
401 }
402
initialize_gl()403 void renderer_ogl::initialize_gl()
404 {
405 int has_and_allow_texturerect = 0;
406
407 char *extstr = (char *)glGetString(GL_EXTENSIONS);
408 char *vendor = (char *)glGetString(GL_VENDOR);
409
410 //printf("%p\n", extstr);
411 #ifdef OSD_WINDOWS
412 if (!extstr)
413 extstr = (char *)"";
414 #endif
415 // print out the driver info for debugging
416 if (!s_shown_video_info)
417 {
418 osd_printf_verbose("OpenGL: %s\nOpenGL: %s\nOpenGL: %s\n", vendor, (char *)glGetString(GL_RENDERER), (char *)glGetString(GL_VERSION));
419 }
420
421 m_usetexturerect = 0;
422 m_texpoweroftwo = 1;
423 m_usevbo = 0;
424 m_usepbo = 0;
425 m_usefbo = 0;
426 m_useglsl = 0;
427
428 if (video_config.allowtexturerect && (strstr(extstr, "GL_ARB_texture_rectangle") || strstr(extstr, "GL_EXT_texture_rectangle")))
429 {
430 has_and_allow_texturerect = 1;
431 if (!s_shown_video_info)
432 {
433 osd_printf_verbose("OpenGL: texture rectangle supported\n");
434 }
435 }
436
437 // does this card support non-power-of-two sized textures? (they're faster, so use them if possible)
438 if ( !video_config.forcepow2texture && strstr(extstr, "GL_ARB_texture_non_power_of_two"))
439 {
440 if (!s_shown_video_info)
441 {
442 osd_printf_verbose("OpenGL: non-power-of-2 textures supported (new method)\n");
443 }
444 m_texpoweroftwo = 0;
445 }
446 else
447 {
448 // second chance: GL_ARB_texture_rectangle or GL_EXT_texture_rectangle (old version)
449 if (has_and_allow_texturerect)
450 {
451 if (!s_shown_video_info)
452 {
453 osd_printf_verbose("OpenGL: non-power-of-2 textures supported (old method)\n");
454 }
455 m_usetexturerect = 1;
456 }
457 else
458 {
459 if (!s_shown_video_info)
460 {
461 osd_printf_verbose("OpenGL: forcing power-of-2 textures (creation, not copy)\n");
462 }
463 }
464 }
465
466 if (strstr(extstr, "GL_ARB_vertex_buffer_object"))
467 {
468 m_usevbo = video_config.vbo;
469 if (!s_shown_video_info)
470 {
471 if(m_usevbo)
472 osd_printf_verbose("OpenGL: vertex buffer supported\n");
473 else
474 osd_printf_verbose("OpenGL: vertex buffer supported, but disabled\n");
475 }
476 }
477
478 if (strstr(extstr, "GL_ARB_pixel_buffer_object"))
479 {
480 if( m_usevbo )
481 {
482 m_usepbo = video_config.pbo;
483 if (!s_shown_video_info)
484 {
485 if(m_usepbo)
486 osd_printf_verbose("OpenGL: pixel buffers supported\n");
487 else
488 osd_printf_verbose("OpenGL: pixel buffers supported, but disabled\n");
489 }
490 }
491 else
492 {
493 if (!s_shown_video_info)
494 {
495 osd_printf_verbose("OpenGL: pixel buffers supported, but disabled due to disabled vbo\n");
496 }
497 }
498 }
499 else
500 {
501 if (!s_shown_video_info)
502 {
503 osd_printf_verbose("OpenGL: pixel buffers not supported\n");
504 }
505 }
506
507 if (strstr(extstr, "GL_EXT_framebuffer_object"))
508 {
509 m_usefbo = 1;
510 if (!s_shown_video_info)
511 {
512 if(m_usefbo)
513 osd_printf_verbose("OpenGL: framebuffer object supported\n");
514 else
515 osd_printf_verbose("OpenGL: framebuffer object not supported\n");
516 }
517 }
518
519 if (strstr(extstr, "GL_ARB_shader_objects") &&
520 strstr(extstr, "GL_ARB_shading_language_100") &&
521 strstr(extstr, "GL_ARB_vertex_shader") &&
522 strstr(extstr, "GL_ARB_fragment_shader")
523 )
524 {
525 m_useglsl = video_config.glsl;
526 if (!s_shown_video_info)
527 {
528 if(m_useglsl)
529 osd_printf_verbose("OpenGL: GLSL supported\n");
530 else
531 osd_printf_verbose("OpenGL: GLSL supported, but disabled\n");
532 }
533 }
534 else
535 {
536 if (!s_shown_video_info)
537 {
538 osd_printf_verbose("OpenGL: GLSL not supported\n");
539 }
540 }
541
542 #ifdef TOBEMIGRATED
543 if (osd_getenv(SDLENV_VMWARE) != nullptr)
544 {
545 m_usetexturerect = 1;
546 m_texpoweroftwo = 1;
547 }
548 #endif
549 glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&m_texture_max_width);
550 glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&m_texture_max_height);
551 if (!s_shown_video_info)
552 {
553 osd_printf_verbose("OpenGL: max texture size %d x %d\n", m_texture_max_width, m_texture_max_height);
554 }
555
556 s_shown_video_info = true;
557
558 }
559 //============================================================
560 // sdl_info::create
561 //============================================================
562
create()563 int renderer_ogl::create()
564 {
565 auto win = assert_window();
566
567 // create renderer
568 #if defined(OSD_WINDOWS)
569 m_gl_context = new win_gl_context(std::static_pointer_cast<win_window_info>(win)->platform_window());
570 #elif defined(OSD_MAC)
571 // TODO
572 // m_gl_context = new mac_gl_context(std::static_pointer_cast<mac_window_info>(win)->platform_window());
573 #else
574 m_gl_context = new sdl_gl_context(std::static_pointer_cast<sdl_window_info>(win)->platform_window());
575 #endif
576 if (m_gl_context->LastErrorMsg() != nullptr)
577 {
578 osd_printf_error("%s\n", m_gl_context->LastErrorMsg());
579 return 1;
580 }
581 m_gl_context->SetSwapInterval(video_config.waitvsync ? 1 : 0);
582
583
584 m_blittimer = 0;
585 m_surf_w = 0;
586 m_surf_h = 0;
587
588 m_initialized = 0;
589
590 // in case any textures try to come up before these are validated,
591 // OpenGL guarantees all implementations can handle something this size.
592 m_texture_max_width = 64;
593 m_texture_max_height = 64;
594
595 /* load any GL function addresses
596 * this must be done here because we need a context
597 */
598 loadgl_functions(m_gl_context);
599 initialize_gl();
600
601
602 m_init_context = 0;
603
604 osd_printf_verbose("Leave renderer_ogl::create\n");
605 return 0;
606 }
607
608
609 //============================================================
610 // drawsdl_xy_to_render_target
611 //============================================================
612 #ifndef OSD_WINDOWS
xy_to_render_target(int x,int y,int * xt,int * yt)613 int renderer_ogl::xy_to_render_target(int x, int y, int *xt, int *yt)
614 {
615 *xt = x - m_last_hofs;
616 *yt = y - m_last_vofs;
617 if (*xt<0 || *xt >= m_blit_dim.width())
618 return 0;
619 if (*yt<0 || *yt >= m_blit_dim.height())
620 return 0;
621 return 1;
622 }
623 #endif
624
625 //============================================================
626 // renderer_ogl::destroy_all_textures
627 //============================================================
628
destroy_all_textures()629 void renderer_ogl::destroy_all_textures()
630 {
631 ogl_texture_info *texture = nullptr;
632 bool lock=false;
633 int i;
634
635 if ( !m_initialized )
636 return;
637
638 auto win = try_getwindow();
639
640 // During destroy this can get called
641 // and the window is no longer available
642 if (win == nullptr)
643 return;
644
645 m_gl_context->MakeCurrent();
646
647 if(win->m_primlist)
648 {
649 lock=true;
650 win->m_primlist->acquire_lock();
651 }
652
653 glFinish();
654
655 texture_all_disable();
656 glFinish();
657 glDisableClientState(GL_VERTEX_ARRAY);
658
659 i=0;
660 while (i<HASH_SIZE+OVERFLOW_SIZE)
661 {
662 texture = m_texhash[i];
663 m_texhash[i] = nullptr;
664 if (texture != nullptr)
665 {
666 if(m_usevbo)
667 {
668 pfn_glDeleteBuffers( 1, &(texture->texCoordBufferName) );
669 texture->texCoordBufferName=0;
670 }
671
672 if(m_usepbo && texture->pbo)
673 {
674 pfn_glDeleteBuffers( 1, (GLuint *)&(texture->pbo) );
675 texture->pbo=0;
676 }
677
678 if( m_glsl_program_num > 1 )
679 {
680 assert(m_usefbo);
681 pfn_glDeleteFramebuffers(2, (GLuint *)&texture->mpass_fbo_mamebm[0]);
682 glDeleteTextures(2, (GLuint *)&texture->mpass_texture_mamebm[0]);
683 }
684
685 if ( m_glsl_program_mb2sc < m_glsl_program_num - 1 )
686 {
687 assert(m_usefbo);
688 pfn_glDeleteFramebuffers(2, (GLuint *)&texture->mpass_fbo_scrn[0]);
689 glDeleteTextures(2, (GLuint *)&texture->mpass_texture_scrn[0]);
690 }
691
692 glDeleteTextures(1, (GLuint *)&texture->texture);
693 if ( texture->data_own )
694 {
695 free(texture->data);
696 texture->data=nullptr;
697 texture->data_own=false;
698 }
699 delete texture;
700 }
701 i++;
702 }
703 if ( m_useglsl )
704 {
705 glsl_shader_free(m_glsl);
706 m_glsl = nullptr;
707 }
708
709 m_initialized = 0;
710
711 if (lock)
712 win->m_primlist->release_lock();
713 }
714 //============================================================
715 // loadGLExtensions
716 //============================================================
717
loadGLExtensions()718 void renderer_ogl::loadGLExtensions()
719 {
720 static int _once = 1;
721
722 // usevbo=false; // You may want to switch VBO and PBO off, by uncommenting this statement
723 // usepbo=false; // You may want to switch PBO off, by uncommenting this statement
724 // useglsl=false; // You may want to switch GLSL off, by uncommenting this statement
725
726 if (! m_usevbo)
727 {
728 if(m_usepbo) // should never ever happen ;-)
729 {
730 if (_once)
731 {
732 osd_printf_warning("OpenGL: PBO not supported, no VBO support. (sdlmame error)\n");
733 }
734 m_usepbo=false;
735 }
736 if(m_useglsl) // should never ever happen ;-)
737 {
738 if (_once)
739 {
740 osd_printf_warning("OpenGL: GLSL not supported, no VBO support. (sdlmame error)\n");
741 }
742 m_useglsl=false;
743 }
744 }
745
746 // Get Pointers To The GL Functions
747 // VBO:
748 if( m_usevbo )
749 {
750 pfn_glGenBuffers = (PFNGLGENBUFFERSPROC) m_gl_context->getProcAddress("glGenBuffers");
751 pfn_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) m_gl_context->getProcAddress("glDeleteBuffers");
752 pfn_glBindBuffer = (PFNGLBINDBUFFERPROC) m_gl_context->getProcAddress("glBindBuffer");
753 pfn_glBufferData = (PFNGLBUFFERDATAPROC) m_gl_context->getProcAddress("glBufferData");
754 pfn_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) m_gl_context->getProcAddress("glBufferSubData");
755 }
756 // PBO:
757 if ( m_usepbo )
758 {
759 pfn_glMapBuffer = (PFNGLMAPBUFFERPROC) m_gl_context->getProcAddress("glMapBuffer");
760 pfn_glUnmapBuffer= (PFNGLUNMAPBUFFERPROC) m_gl_context->getProcAddress("glUnmapBuffer");
761 }
762 // FBO:
763 if ( m_usefbo )
764 {
765 pfn_glIsFramebuffer = (PFNGLISFRAMEBUFFEREXTPROC) m_gl_context->getProcAddress("glIsFramebufferEXT");
766 pfn_glBindFramebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC) m_gl_context->getProcAddress("glBindFramebufferEXT");
767 pfn_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSEXTPROC) m_gl_context->getProcAddress("glDeleteFramebuffersEXT");
768 pfn_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC) m_gl_context->getProcAddress("glGenFramebuffersEXT");
769 pfn_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) m_gl_context->getProcAddress("glCheckFramebufferStatusEXT");
770 pfn_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) m_gl_context->getProcAddress("glFramebufferTexture2DEXT");
771 }
772
773 if ( m_usevbo &&
774 ( !pfn_glGenBuffers || !pfn_glDeleteBuffers ||
775 !pfn_glBindBuffer || !pfn_glBufferData || !pfn_glBufferSubData
776 ) )
777 {
778 m_usepbo=false;
779 if (_once)
780 {
781 osd_printf_warning("OpenGL: VBO not supported, missing: ");
782 if (!pfn_glGenBuffers)
783 {
784 osd_printf_warning("glGenBuffers, ");
785 }
786 if (!pfn_glDeleteBuffers)
787 {
788 osd_printf_warning("glDeleteBuffers");
789 }
790 if (!pfn_glBindBuffer)
791 {
792 osd_printf_warning("glBindBuffer, ");
793 }
794 if (!pfn_glBufferData)
795 {
796 osd_printf_warning("glBufferData, ");
797 }
798 if (!pfn_glBufferSubData)
799 {
800 osd_printf_warning("glBufferSubData, ");
801 }
802 osd_printf_warning("\n");
803 }
804 if ( m_usevbo )
805 {
806 if (_once)
807 {
808 osd_printf_warning("OpenGL: PBO not supported, no VBO support.\n");
809 }
810 m_usepbo=false;
811 }
812 }
813
814 if ( m_usepbo && ( !pfn_glMapBuffer || !pfn_glUnmapBuffer ) )
815 {
816 m_usepbo=false;
817 if (_once)
818 {
819 osd_printf_warning("OpenGL: PBO not supported, missing: ");
820 if (!pfn_glMapBuffer)
821 {
822 osd_printf_warning("glMapBuffer, ");
823 }
824 if (!pfn_glUnmapBuffer)
825 {
826 osd_printf_warning("glUnmapBuffer, ");
827 }
828 osd_printf_warning("\n");
829 }
830 }
831
832 if ( m_usefbo &&
833 ( !pfn_glIsFramebuffer || !pfn_glBindFramebuffer || !pfn_glDeleteFramebuffers ||
834 !pfn_glGenFramebuffers || !pfn_glCheckFramebufferStatus || !pfn_glFramebufferTexture2D
835 ))
836 {
837 m_usefbo=false;
838 if (_once)
839 {
840 osd_printf_warning("OpenGL: FBO not supported, missing: ");
841 if (!pfn_glIsFramebuffer)
842 {
843 osd_printf_warning("pfn_glIsFramebuffer, ");
844 }
845 if (!pfn_glBindFramebuffer)
846 {
847 osd_printf_warning("pfn_glBindFramebuffer, ");
848 }
849 if (!pfn_glDeleteFramebuffers)
850 {
851 osd_printf_warning("pfn_glDeleteFramebuffers, ");
852 }
853 if (!pfn_glGenFramebuffers)
854 {
855 osd_printf_warning("pfn_glGenFramebuffers, ");
856 }
857 if (!pfn_glCheckFramebufferStatus)
858 {
859 osd_printf_warning("pfn_glCheckFramebufferStatus, ");
860 }
861 if (!pfn_glFramebufferTexture2D)
862 {
863 osd_printf_warning("pfn_glFramebufferTexture2D, ");
864 }
865 osd_printf_warning("\n");
866 }
867 }
868
869 if (_once)
870 {
871 if ( m_usevbo )
872 {
873 osd_printf_verbose("OpenGL: VBO supported\n");
874 }
875 else
876 {
877 osd_printf_warning("OpenGL: VBO not supported\n");
878 }
879
880 if ( m_usepbo )
881 {
882 osd_printf_verbose("OpenGL: PBO supported\n");
883 }
884 else
885 {
886 osd_printf_warning("OpenGL: PBO not supported\n");
887 }
888
889 if ( m_usefbo )
890 {
891 osd_printf_verbose("OpenGL: FBO supported\n");
892 }
893 else
894 {
895 osd_printf_warning("OpenGL: FBO not supported\n");
896 }
897 }
898
899 if ( m_useglsl )
900 {
901 #if defined(GL_ARB_multitexture) && !defined(OSD_MAC)
902 pfn_glActiveTexture = (PFNGLACTIVETEXTUREARBPROC) m_gl_context->getProcAddress("glActiveTextureARB");
903 #else
904 pfn_glActiveTexture = (PFNGLACTIVETEXTUREPROC) m_gl_context->getProcAddress("glActiveTexture");
905 #endif
906 if (!pfn_glActiveTexture)
907 {
908 if (_once)
909 {
910 osd_printf_warning("OpenGL: GLSL disabled, glActiveTexture(ARB) not supported\n");
911 }
912 m_useglsl = 0;
913 }
914 }
915
916 if ( m_useglsl )
917 {
918 m_glsl = glsl_shader_init(m_gl_context);
919 m_useglsl = (m_glsl != nullptr ? 1 : 0);
920
921 if ( ! m_useglsl )
922 {
923 if (_once)
924 {
925 osd_printf_warning("OpenGL: GLSL supported, but shader instantiation failed - disabled\n");
926 }
927 }
928 }
929
930 if ( m_useglsl )
931 {
932 if (assert_window()->prescale() != 1 )
933 {
934 m_useglsl = 0;
935 if (_once)
936 {
937 osd_printf_warning("OpenGL: GLSL supported, but disabled due to: prescale !=1 \n");
938 }
939 }
940 }
941
942 if ( m_useglsl )
943 {
944 int i;
945 video_config.filter = false;
946 glsl_shader_feature = GLSL_SHADER_FEAT_PLAIN;
947 m_glsl_program_num = 0;
948 m_glsl_program_mb2sc = 0;
949
950 for(i=0; i<video_config.glsl_shader_mamebm_num; i++)
951 {
952 if ( !m_usefbo && m_glsl_program_num==1 )
953 {
954 if (_once)
955 {
956 osd_printf_verbose("OpenGL: GLSL multipass not supported, due to unsupported FBO. Skipping followup shader\n");
957 }
958 break;
959 }
960
961 if ( glsl_shader_add_mamebm(m_glsl, video_config.glsl_shader_mamebm[i], m_glsl_program_num) )
962 {
963 osd_printf_error("OpenGL: GLSL loading mame bitmap shader %d failed (%s)\n",
964 i, video_config.glsl_shader_mamebm[i]);
965 } else {
966 glsl_shader_feature = GLSL_SHADER_FEAT_CUSTOM;
967 if (_once)
968 {
969 osd_printf_verbose("OpenGL: GLSL using mame bitmap shader filter %d: '%s'\n",
970 m_glsl_program_num, video_config.glsl_shader_mamebm[i]);
971 }
972 m_glsl_program_mb2sc = m_glsl_program_num; // the last mame_bitmap (mb) shader does it.
973 m_glsl_program_num++;
974 }
975 }
976
977 if ( video_config.glsl_shader_scrn_num > 0 && m_glsl_program_num==0 )
978 {
979 osd_printf_verbose("OpenGL: GLSL cannot use screen bitmap shader without bitmap shader\n");
980 }
981
982 for(i=0; m_usefbo && m_glsl_program_num>0 && i<video_config.glsl_shader_scrn_num; i++)
983 {
984 if ( glsl_shader_add_scrn(m_glsl, video_config.glsl_shader_scrn[i],
985 m_glsl_program_num-1-m_glsl_program_mb2sc) )
986 {
987 osd_printf_error("OpenGL: GLSL loading screen bitmap shader %d failed (%s)\n",
988 i, video_config.glsl_shader_scrn[i]);
989 } else {
990 if (_once)
991 {
992 osd_printf_verbose("OpenGL: GLSL using screen bitmap shader filter %d: '%s'\n",
993 m_glsl_program_num, video_config.glsl_shader_scrn[i]);
994 }
995 m_glsl_program_num++;
996 }
997 }
998
999 if ( 0==m_glsl_program_num &&
1000 0 <= video_config.glsl_filter && video_config.glsl_filter < GLSL_SHADER_FEAT_INT_NUMBER )
1001 {
1002 m_glsl_program_mb2sc = m_glsl_program_num; // the last mame_bitmap (mb) shader does it.
1003 m_glsl_program_num++;
1004 glsl_shader_feature = video_config.glsl_filter;
1005
1006 if (_once)
1007 {
1008 osd_printf_verbose("OpenGL: GLSL using shader filter '%s', idx: %d, num %d (vid filter: %d)\n",
1009 glsl_shader_get_filter_name_mamebm(glsl_shader_feature),
1010 glsl_shader_feature, m_glsl_program_num, video_config.filter);
1011 }
1012 }
1013
1014 } else {
1015 if (_once)
1016 {
1017 osd_printf_verbose("OpenGL: using vid filter: %d\n", video_config.filter);
1018 }
1019 }
1020
1021 _once = 0;
1022 }
1023
1024 //============================================================
1025 // sdl_info::draw
1026 //============================================================
1027
draw(const int update)1028 int renderer_ogl::draw(const int update)
1029 {
1030 ogl_texture_info *texture=nullptr;
1031 float vofs, hofs;
1032 int pendingPrimitive=GL_NO_PRIMITIVE, curPrimitive=GL_NO_PRIMITIVE;
1033
1034 #ifdef TOBEMIGRATED
1035 if (video_config.novideo)
1036 {
1037 return 0;
1038 }
1039 #endif
1040
1041 auto win = assert_window();
1042
1043 osd_dim wdim = win->get_size();
1044
1045 if (has_flags(FI_CHANGED) || (wdim.width() != m_width) || (wdim.height() != m_height))
1046 {
1047 destroy_all_textures();
1048 m_width = wdim.width();
1049 m_height = wdim.height();
1050 m_blittimer = 3;
1051 m_init_context = 1;
1052 clear_flags(FI_CHANGED);
1053 }
1054
1055 m_gl_context->MakeCurrent();
1056
1057 if (m_init_context)
1058 {
1059 // do some one-time OpenGL setup
1060 // FIXME: SRGB conversion is working on SDL2, may be of use
1061 // when we eventually target gamma and monitor profiles.
1062 //glEnable(GL_FRAMEBUFFER_SRGB);
1063 glShadeModel(GL_SMOOTH);
1064 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1065 glClearDepth(1.0f);
1066 glEnable(GL_DEPTH_TEST);
1067 glDepthFunc(GL_LEQUAL);
1068 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
1069 }
1070
1071 // only clear if the geometry changes (and for 2 frames afterward to clear double and triple buffers)
1072 if ((m_blittimer > 0) || has_flags(FLAG_HAS_VECTOR_SCREEN))
1073 {
1074 glClear(GL_COLOR_BUFFER_BIT);
1075 m_blittimer--;
1076 }
1077
1078 // FIXME: remove m_surf_w and m_surf_h
1079 if ( !m_initialized ||
1080 m_width != m_surf_w || m_height != m_surf_h )
1081 {
1082 // FIXME:: this can be done in create!
1083 if ( !m_initialized )
1084 {
1085 loadGLExtensions();
1086 }
1087
1088 m_surf_w = m_width;
1089 m_surf_h = m_height;
1090
1091 // we're doing nothing 3d, so the Z-buffer is currently not interesting
1092 glDisable(GL_DEPTH_TEST);
1093
1094 // enable antialiasing for lines
1095 glEnable(GL_LINE_SMOOTH);
1096 // enable antialiasing for points
1097 glEnable(GL_POINT_SMOOTH);
1098
1099 // prefer quality to speed
1100 glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
1101 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
1102
1103 // enable blending
1104 glEnable(GL_BLEND);
1105 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1106 m_last_blendmode = BLENDMODE_ALPHA;
1107
1108 #ifdef TOBEMIGRATED
1109 // set lines and points just barely above normal size to get proper results
1110 glLineWidth(video_config.beamwidth);
1111 glPointSize(video_config.beamwidth);
1112 #endif
1113
1114 // set up a nice simple 2D coordinate system, so GL behaves exactly how we'd like.
1115 //
1116 // (0,0) (w,0)
1117 // |~~~~~~~~~|
1118 // | |
1119 // | |
1120 // | |
1121 // |_________|
1122 // (0,h) (w,h)
1123
1124 GLsizei iScale = 1;
1125
1126 /*
1127 Mac hack: macOS version 10.15 and later flipped from assuming you don't support Retina to
1128 assuming you do support Retina. SDL 2.0.11 is scheduled to fix this, but it's not out yet.
1129 So we double-scale everything if you're on 10.15 or later and SDL is not at least version 2.0.11.
1130 */
1131 #if defined(SDLMAME_MACOSX) || defined(OSD_MAC)
1132 SDL_version sdlVers;
1133 SDL_GetVersion(&sdlVers);
1134 // Only do this if SDL is not at least 2.0.11.
1135 if ((sdlVers.major == 2) && (sdlVers.minor == 0) && (sdlVers.patch < 11))
1136 {
1137 // now get the Darwin kernel version
1138 int dMaj, dMin, dPatch;
1139 char versStr[64];
1140 dMaj = dMin = dPatch = 0;
1141 size_t size = sizeof(versStr);
1142 int retVal = sysctlbyname("kern.osrelease", versStr, &size, NULL, 0);
1143 if (retVal == 0)
1144 {
1145 sscanf(versStr, "%d.%d.%d", &dMaj, &dMin, &dPatch);
1146 // 10.15 Catalina is Darwin version 19
1147 if (dMaj >= 19)
1148 {
1149 // do the workaround for Retina being forced on
1150 osd_printf_verbose("OpenGL: enabling Retina workaround\n");
1151 iScale = 2;
1152 }
1153 }
1154 }
1155 #endif
1156
1157 glViewport(0.0, 0.0, (GLsizei) m_width * iScale, (GLsizei) m_height * iScale);
1158 glMatrixMode(GL_PROJECTION);
1159 glLoadIdentity();
1160 glOrtho(0.0, (GLdouble) m_width, (GLdouble) m_height, 0.0, 0.0, -1.0);
1161 glMatrixMode(GL_MODELVIEW);
1162 glLoadIdentity();
1163
1164 if ( ! m_initialized )
1165 {
1166 glEnableClientState(GL_VERTEX_ARRAY);
1167 glVertexPointer(2, GL_FLOAT, 0, m_texVerticex); // no VBO, since it's too volatile
1168
1169 m_initialized = 1;
1170 }
1171 }
1172
1173 // compute centering parameters
1174 vofs = hofs = 0.0f;
1175
1176 #ifdef TOBEMIGRATED
1177 if (video_config.centerv || video_config.centerh)
1178 {
1179 int ch, cw;
1180
1181 ch = m_height;
1182 cw = m_width;
1183
1184 if (video_config.centerv)
1185 {
1186 vofs = (ch - m_blit_dim.height()) / 2.0f;
1187 }
1188 if (video_config.centerh)
1189 {
1190 hofs = (cw - m_blit_dim.width()) / 2.0f;
1191 }
1192 }
1193 #else
1194 #endif
1195
1196 m_last_hofs = hofs;
1197 m_last_vofs = vofs;
1198
1199 win->m_primlist->acquire_lock();
1200
1201 // now draw
1202 for (render_primitive &prim : *win->m_primlist)
1203 {
1204 int i;
1205
1206 switch (prim.type)
1207 {
1208 /**
1209 * Try to stay in one Begin/End block as long as possible,
1210 * since entering and leaving one is most expensive..
1211 */
1212 case render_primitive::LINE:
1213 #if !USE_WIN32_STYLE_LINES
1214 // check if it's really a point
1215 if (((prim.bounds.x1 - prim.bounds.x0) == 0) && ((prim.bounds.y1 - prim.bounds.y0) == 0))
1216 {
1217 curPrimitive=GL_POINTS;
1218 } else {
1219 curPrimitive=GL_LINES;
1220 }
1221
1222 if(pendingPrimitive!=GL_NO_PRIMITIVE && pendingPrimitive!=curPrimitive)
1223 {
1224 glEnd();
1225 pendingPrimitive=GL_NO_PRIMITIVE;
1226 }
1227
1228 if ( pendingPrimitive==GL_NO_PRIMITIVE )
1229 {
1230 set_blendmode(PRIMFLAG_GET_BLENDMODE(prim.flags));
1231 }
1232
1233 glColor4f(prim.color.r, prim.color.g, prim.color.b, prim.color.a);
1234
1235 if(pendingPrimitive!=curPrimitive)
1236 {
1237 glLineWidth(prim.width);
1238 glBegin(curPrimitive);
1239 pendingPrimitive=curPrimitive;
1240 }
1241
1242 // check if it's really a point
1243 if (curPrimitive==GL_POINTS)
1244 {
1245 glVertex2f(prim.bounds.x0+hofs, prim.bounds.y0+vofs);
1246 }
1247 else
1248 {
1249 glVertex2f(prim.bounds.x0+hofs, prim.bounds.y0+vofs);
1250 glVertex2f(prim.bounds.x1+hofs, prim.bounds.y1+vofs);
1251 }
1252 #else
1253 {
1254 const line_aa_step *step = line_aa_4step;
1255 render_bounds b0, b1;
1256 float r, g, b, a;
1257 float effwidth;
1258
1259 // we're not gonna play fancy here. close anything pending and let's go.
1260 if (pendingPrimitive!=GL_NO_PRIMITIVE && pendingPrimitive!=curPrimitive)
1261 {
1262 glEnd();
1263 pendingPrimitive=GL_NO_PRIMITIVE;
1264 }
1265
1266 set_blendmode(sdl, PRIMFLAG_GET_BLENDMODE(prim.flags));
1267
1268 // compute the effective width based on the direction of the line
1269 effwidth = prim.width();
1270 if (effwidth < 0.5f)
1271 effwidth = 0.5f;
1272
1273 // determine the bounds of a quad to draw this line
1274 render_line_to_quad(&prim.bounds, effwidth, 0.0f, &b0, &b1);
1275
1276 // fix window position
1277 b0.x0 += hofs;
1278 b0.x1 += hofs;
1279 b1.x0 += hofs;
1280 b1.x1 += hofs;
1281 b0.y0 += vofs;
1282 b0.y1 += vofs;
1283 b1.y0 += vofs;
1284 b1.y1 += vofs;
1285
1286 // iterate over AA steps
1287 for (step = PRIMFLAG_GET_ANTIALIAS(prim.flags) ? line_aa_4step : line_aa_1step; step->weight != 0; step++)
1288 {
1289 glBegin(GL_TRIANGLE_STRIP);
1290
1291 // rotate the unit vector by 135 degrees and add to point 0
1292 glVertex2f(b0.x0 + step->xoffs, b0.y0 + step->yoffs);
1293
1294 // rotate the unit vector by -135 degrees and add to point 0
1295 glVertex2f(b0.x1 + step->xoffs, b0.y1 + step->yoffs);
1296
1297 // rotate the unit vector by 45 degrees and add to point 1
1298 glVertex2f(b1.x0 + step->xoffs, b1.y0 + step->yoffs);
1299
1300 // rotate the unit vector by -45 degrees and add to point 1
1301 glVertex2f(b1.x1 + step->xoffs, b1.y1 + step->yoffs);
1302
1303 // determine the color of the line
1304 r = (prim.color.r * step->weight);
1305 g = (prim.color.g * step->weight);
1306 b = (prim.color.b * step->weight);
1307 a = (prim.color.a * 255.0f);
1308 if (r > 1.0) r = 1.0;
1309 if (g > 1.0) g = 1.0;
1310 if (b > 1.0) b = 1.0;
1311 if (a > 1.0) a = 1.0;
1312 glColor4f(r, g, b, a);
1313
1314 // texture = texture_update(window, &prim, 0);
1315 // if (texture) printf("line has texture!\n");
1316
1317 // if we have a texture to use for the vectors, use it here
1318 #if 0
1319 if (d3d->vector_texture != nullptr)
1320 {
1321 printf("SDL: textured lines unsupported\n");
1322 vertex[0].u0 = d3d->vector_texture->ustart;
1323 vertex[0].v0 = d3d->vector_texture->vstart;
1324
1325 vertex[2].u0 = d3d->vector_texture->ustop;
1326 vertex[2].v0 = d3d->vector_texture->vstart;
1327
1328 vertex[1].u0 = d3d->vector_texture->ustart;
1329 vertex[1].v0 = d3d->vector_texture->vstop;
1330
1331 vertex[3].u0 = d3d->vector_texture->ustop;
1332 vertex[3].v0 = d3d->vector_texture->vstop;
1333 }
1334 #endif
1335 glEnd();
1336 }
1337 }
1338 #endif
1339 break;
1340
1341 case render_primitive::QUAD:
1342
1343 if(pendingPrimitive!=GL_NO_PRIMITIVE)
1344 {
1345 glEnd();
1346 pendingPrimitive=GL_NO_PRIMITIVE;
1347 }
1348
1349 glColor4f(prim.color.r, prim.color.g, prim.color.b, prim.color.a);
1350
1351 set_blendmode(PRIMFLAG_GET_BLENDMODE(prim.flags));
1352
1353 texture = texture_update(&prim, 0);
1354
1355 if ( texture && texture->type==TEXTURE_TYPE_SHADER )
1356 {
1357 for(i=0; i<m_glsl_program_num; i++)
1358 {
1359 if ( i==m_glsl_program_mb2sc )
1360 {
1361 // i==glsl_program_mb2sc -> transformation mamebm->scrn
1362 m_texVerticex[0]=prim.bounds.x0 + hofs;
1363 m_texVerticex[1]=prim.bounds.y0 + vofs;
1364 m_texVerticex[2]=prim.bounds.x1 + hofs;
1365 m_texVerticex[3]=prim.bounds.y0 + vofs;
1366 m_texVerticex[4]=prim.bounds.x1 + hofs;
1367 m_texVerticex[5]=prim.bounds.y1 + vofs;
1368 m_texVerticex[6]=prim.bounds.x0 + hofs;
1369 m_texVerticex[7]=prim.bounds.y1 + vofs;
1370 } else {
1371 // 1:1 tex coord CCW (0/0) (1/0) (1/1) (0/1) on texture dimensions
1372 m_texVerticex[0]=(GLfloat)0.0;
1373 m_texVerticex[1]=(GLfloat)0.0;
1374 m_texVerticex[2]=(GLfloat)m_width;
1375 m_texVerticex[3]=(GLfloat)0.0;
1376 m_texVerticex[4]=(GLfloat)m_width;
1377 m_texVerticex[5]=(GLfloat)m_height;
1378 m_texVerticex[6]=(GLfloat)0.0;
1379 m_texVerticex[7]=(GLfloat)m_height;
1380 }
1381
1382 if(i>0) // first fetch already done
1383 {
1384 texture = texture_update(&prim, i);
1385 }
1386 glDrawArrays(GL_QUADS, 0, 4);
1387 }
1388 } else {
1389 m_texVerticex[0]=prim.bounds.x0 + hofs;
1390 m_texVerticex[1]=prim.bounds.y0 + vofs;
1391 m_texVerticex[2]=prim.bounds.x1 + hofs;
1392 m_texVerticex[3]=prim.bounds.y0 + vofs;
1393 m_texVerticex[4]=prim.bounds.x1 + hofs;
1394 m_texVerticex[5]=prim.bounds.y1 + vofs;
1395 m_texVerticex[6]=prim.bounds.x0 + hofs;
1396 m_texVerticex[7]=prim.bounds.y1 + vofs;
1397
1398 glDrawArrays(GL_QUADS, 0, 4);
1399 }
1400
1401 if ( texture )
1402 {
1403 texture_disable(texture);
1404 texture=nullptr;
1405 }
1406 break;
1407
1408 default:
1409 throw emu_fatalerror("Unexpected render_primitive type");
1410 }
1411 }
1412
1413 if(pendingPrimitive!=GL_NO_PRIMITIVE)
1414 {
1415 glEnd();
1416 pendingPrimitive=GL_NO_PRIMITIVE;
1417 }
1418
1419 win->m_primlist->release_lock();
1420 m_init_context = 0;
1421
1422 m_gl_context->SwapBuffer();
1423
1424 return 0;
1425 }
1426
1427 //============================================================
1428 // texture handling
1429 //============================================================
1430
1431 static const char * texfmt_to_string[9] = {
1432 "ARGB32",
1433 "RGB32",
1434 "RGB32_PALETTED",
1435 "YUV16",
1436 "YUV16_PALETTED",
1437 "PALETTE16",
1438 "RGB15",
1439 "RGB15_PALETTE",
1440 "PALETTE16A"
1441 };
1442
1443 //
1444 // Note: if you change the following array order, change the matching defines in texsrc.h
1445 //
1446
1447 enum { SDL_TEXFORMAT_SRC_EQUALS_DEST, SDL_TEXFORMAT_SRC_HAS_PALETTE };
1448
1449 static const GLint texture_copy_properties[9][2] = {
1450 { true, false }, // SDL_TEXFORMAT_ARGB32
1451 { true, false }, // SDL_TEXFORMAT_RGB32
1452 { true, true }, // SDL_TEXFORMAT_RGB32_PALETTED
1453 { false, false }, // SDL_TEXFORMAT_YUY16
1454 { false, true }, // SDL_TEXFORMAT_YUY16_PALETTED
1455 { false, true }, // SDL_TEXFORMAT_PALETTE16
1456 { true, false }, // SDL_TEXFORMAT_RGB15
1457 { true, true }, // SDL_TEXFORMAT_RGB15_PALETTED
1458 { false, true } // SDL_TEXFORMAT_PALETTE16A
1459 };
1460
1461 //============================================================
1462 // texture_compute_size and type
1463 //============================================================
1464
1465 //
1466 // glBufferData to push a nocopy texture to the GPU is slower than TexSubImage2D,
1467 // so don't use PBO here
1468 //
1469 // we also don't want to use PBO's in the case of nocopy==true,
1470 // since we now might have GLSL shaders - this decision simplifies out life ;-)
1471 //
texture_compute_type_subroutine(const render_texinfo * texsource,ogl_texture_info * texture,uint32_t flags)1472 void renderer_ogl::texture_compute_type_subroutine(const render_texinfo *texsource, ogl_texture_info *texture, uint32_t flags)
1473 {
1474 texture->type = TEXTURE_TYPE_NONE;
1475 texture->nocopy = false;
1476
1477 if ( texture->type == TEXTURE_TYPE_NONE &&
1478 !PRIMFLAG_GET_SCREENTEX(flags))
1479 {
1480 texture->type = TEXTURE_TYPE_PLAIN;
1481 texture->texTarget = (m_usetexturerect)?GL_TEXTURE_RECTANGLE_ARB:GL_TEXTURE_2D;
1482 texture->texpow2 = (m_usetexturerect)?0:m_texpoweroftwo;
1483 }
1484
1485 if ( texture->type == TEXTURE_TYPE_NONE && m_useglsl &&
1486 texture->xprescale == 1 && texture->yprescale == 1 &&
1487 texsource->rowpixels <= m_texture_max_width )
1488 {
1489 texture->type = TEXTURE_TYPE_SHADER;
1490 texture->texTarget = GL_TEXTURE_2D;
1491 texture->texpow2 = m_texpoweroftwo;
1492 }
1493
1494 // determine if we can skip the copy step
1495 // if this was not already decided by the shader condition above
1496 if ( texture_copy_properties[texture->format][SDL_TEXFORMAT_SRC_EQUALS_DEST] &&
1497 !texture_copy_properties[texture->format][SDL_TEXFORMAT_SRC_HAS_PALETTE] &&
1498 texture->xprescale == 1 && texture->yprescale == 1 &&
1499 !texture->borderpix && !texsource->palette &&
1500 texsource->rowpixels <= m_texture_max_width )
1501 {
1502 texture->nocopy = true;
1503 }
1504
1505 if( texture->type == TEXTURE_TYPE_NONE &&
1506 m_usepbo && !texture->nocopy )
1507 {
1508 texture->type = TEXTURE_TYPE_DYNAMIC;
1509 texture->texTarget = (m_usetexturerect)?GL_TEXTURE_RECTANGLE_ARB:GL_TEXTURE_2D;
1510 texture->texpow2 = (m_usetexturerect)?0:m_texpoweroftwo;
1511 }
1512
1513 if( texture->type == TEXTURE_TYPE_NONE )
1514 {
1515 texture->type = TEXTURE_TYPE_SURFACE;
1516 texture->texTarget = (m_usetexturerect)?GL_TEXTURE_RECTANGLE_ARB:GL_TEXTURE_2D;
1517 texture->texpow2 = (m_usetexturerect)?0:m_texpoweroftwo;
1518 }
1519 }
1520
get_valid_pow2_value(int v,int needPow2)1521 static inline int get_valid_pow2_value(int v, int needPow2)
1522 {
1523 return (needPow2)?gl_round_to_pow2(v):v;
1524 }
1525
texture_compute_size_subroutine(ogl_texture_info * texture,uint32_t flags,uint32_t width,uint32_t height,int * p_width,int * p_height,int * p_width_create,int * p_height_create)1526 void renderer_ogl::texture_compute_size_subroutine(ogl_texture_info *texture, uint32_t flags,
1527 uint32_t width, uint32_t height,
1528 int* p_width, int* p_height, int* p_width_create, int* p_height_create)
1529 {
1530 int width_create;
1531 int height_create;
1532
1533 if ( texture->texpow2 )
1534 {
1535 width_create = gl_round_to_pow2 (width);
1536 height_create = gl_round_to_pow2 (height);
1537 } else if ( texture->type==TEXTURE_TYPE_SHADER )
1538 {
1539 /**
1540 * at least use a multiple of 8 for shader .. just in case
1541 */
1542 width_create = ( width & ~0x07 ) + ( (width & 0x07)? 8 : 0 ) ;
1543 height_create = ( height & ~0x07 ) + ( (height & 0x07)? 8 : 0 ) ;
1544 } else {
1545 width_create = width ;
1546 height_create = height ;
1547 }
1548
1549 // don't prescale above max texture size
1550 while (texture->xprescale > 1 && width_create * texture->xprescale > m_texture_max_width)
1551 texture->xprescale--;
1552 while (texture->yprescale > 1 && height_create * texture->yprescale > m_texture_max_height)
1553 texture->yprescale--;
1554
1555 auto win = assert_window();
1556 if (PRIMFLAG_GET_SCREENTEX(flags) && (texture->xprescale != win->prescale() || texture->yprescale != win->prescale()))
1557 osd_printf_warning("SDL: adjusting prescale from %dx%d to %dx%d\n", win->prescale(), win->prescale(), texture->xprescale, texture->yprescale);
1558
1559 width *= texture->xprescale;
1560 height *= texture->yprescale;
1561 width_create *= texture->xprescale;
1562 height_create *= texture->yprescale;
1563
1564 // adjust the size for the border (must do this *after* the power of 2 clamp to satisfy
1565 // OpenGL semantics)
1566 if (texture->borderpix)
1567 {
1568 width += 2;
1569 height += 2;
1570 width_create += 2;
1571 height_create += 2;
1572 }
1573 *p_width=width;
1574 *p_height=height;
1575 *p_width_create=width_create;
1576 *p_height_create=height_create;
1577 }
1578
texture_compute_size_type(const render_texinfo * texsource,ogl_texture_info * texture,uint32_t flags)1579 void renderer_ogl::texture_compute_size_type(const render_texinfo *texsource, ogl_texture_info *texture, uint32_t flags)
1580 {
1581 int finalheight, finalwidth;
1582 int finalheight_create, finalwidth_create;
1583
1584 // if we're not wrapping, add a 1 pixel border on all sides
1585 texture->borderpix = 0; //!(texture->flags & PRIMFLAG_TEXWRAP_MASK);
1586 if (PRIMFLAG_GET_SCREENTEX(flags))
1587 {
1588 texture->borderpix = 0; // don't border the screen right now, there's a bug
1589 }
1590
1591 texture_compute_type_subroutine(texsource, texture, flags);
1592
1593 texture_compute_size_subroutine(texture, flags, texsource->width, texsource->height,
1594 &finalwidth, &finalheight, &finalwidth_create, &finalheight_create);
1595
1596 // if we added pixels for the border, and that just barely pushed us over, take it back
1597 if (texture->borderpix &&
1598 ((finalwidth > m_texture_max_width && finalwidth - 2 <= m_texture_max_width) ||
1599 (finalheight > m_texture_max_height && finalheight - 2 <= m_texture_max_height)))
1600 {
1601 texture->borderpix = false;
1602
1603 texture_compute_type_subroutine(texsource, texture, flags);
1604
1605 texture_compute_size_subroutine(texture, flags, texsource->width, texsource->height,
1606 &finalwidth, &finalheight, &finalwidth_create, &finalheight_create);
1607 }
1608
1609 // if we're above the max width/height, do what?
1610 if (finalwidth_create > m_texture_max_width || finalheight_create > m_texture_max_height)
1611 {
1612 static int printed = false;
1613 if (!printed)
1614 osd_printf_warning("Texture too big! (wanted: %dx%d, max is %dx%d)\n", finalwidth_create, finalheight_create, m_texture_max_width, m_texture_max_height);
1615 printed = true;
1616 }
1617
1618 if(!texture->nocopy || texture->type==TEXTURE_TYPE_DYNAMIC || texture->type==TEXTURE_TYPE_SHADER ||
1619 // any of the mame core's device generated bitmap types:
1620 texture->format==SDL_TEXFORMAT_RGB32 ||
1621 texture->format==SDL_TEXFORMAT_RGB32_PALETTED ||
1622 texture->format==SDL_TEXFORMAT_RGB15 ||
1623 texture->format==SDL_TEXFORMAT_RGB15_PALETTED ||
1624 texture->format==SDL_TEXFORMAT_PALETTE16 ||
1625 texture->format==SDL_TEXFORMAT_PALETTE16A
1626 )
1627 {
1628 osd_printf_verbose("GL texture: copy %d, shader %d, dynamic %d, %dx%d %dx%d [%s, Equal: %d, Palette: %d,\n"
1629 " scale %dx%d, border %d, pitch %d,%d/%d], bytes/pix %d\n",
1630 !texture->nocopy, texture->type==TEXTURE_TYPE_SHADER, texture->type==TEXTURE_TYPE_DYNAMIC,
1631 finalwidth, finalheight, finalwidth_create, finalheight_create,
1632 texfmt_to_string[texture->format],
1633 (int)texture_copy_properties[texture->format][SDL_TEXFORMAT_SRC_EQUALS_DEST],
1634 (int)texture_copy_properties[texture->format][SDL_TEXFORMAT_SRC_HAS_PALETTE],
1635 texture->xprescale, texture->yprescale,
1636 texture->borderpix, texsource->rowpixels, finalwidth, m_texture_max_width,
1637 (int)sizeof(uint32_t)
1638 );
1639 }
1640
1641 // set the final values
1642 texture->rawwidth = finalwidth;
1643 texture->rawheight = finalheight;
1644 texture->rawwidth_create = finalwidth_create;
1645 texture->rawheight_create = finalheight_create;
1646 }
1647
1648 //============================================================
1649 // texture_create
1650 //============================================================
1651
gl_checkFramebufferStatus()1652 static int gl_checkFramebufferStatus()
1653 {
1654 GLenum status;
1655 status=(GLenum)pfn_glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
1656 switch(status) {
1657 case GL_FRAMEBUFFER_COMPLETE_EXT:
1658 return 0;
1659 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
1660 osd_printf_error("GL FBO: incomplete,incomplete attachment\n");
1661 return -1;
1662 case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
1663 osd_printf_error("GL FBO: Unsupported framebuffer format\n");
1664 return -1;
1665 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
1666 osd_printf_error("GL FBO: incomplete,missing attachment\n");
1667 return -1;
1668 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
1669 osd_printf_error("GL FBO: incomplete,attached images must have same dimensions\n");
1670 return -1;
1671 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
1672 osd_printf_error("GL FBO: incomplete,attached images must have same format\n");
1673 return -1;
1674 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
1675 osd_printf_error("GL FBO: incomplete,missing draw buffer\n");
1676 return -1;
1677 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
1678 osd_printf_error("GL FBO: incomplete,missing read buffer\n");
1679 return -1;
1680 #ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
1681 case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
1682 osd_printf_error("GL FBO: incomplete, duplicate attachment\n");
1683 return -1;
1684 #endif
1685 case 0:
1686 osd_printf_error("GL FBO: incomplete, implementation fault\n");
1687 return -1;
1688 default:
1689 osd_printf_error("GL FBO: incomplete, implementation ERROR\n");
1690 /* fall through */
1691 }
1692 return -1;
1693 }
1694
texture_fbo_create(uint32_t text_unit,uint32_t text_name,uint32_t fbo_name,int width,int height)1695 static int texture_fbo_create(uint32_t text_unit, uint32_t text_name, uint32_t fbo_name, int width, int height)
1696 {
1697 pfn_glActiveTexture(text_unit);
1698 pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo_name);
1699 glBindTexture(GL_TEXTURE_2D, text_name);
1700 {
1701 GLint _width, _height;
1702 if ( gl_texture_check_size(GL_TEXTURE_2D, 0, GL_RGBA8, width, height,
1703 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &_width, &_height, 1) )
1704 {
1705 osd_printf_error("cannot create fbo texture, req: %dx%d, avail: %dx%d - bail out\n",
1706 width, height, (int)_width, (int)_height);
1707 return -1;
1708 }
1709
1710 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height,
1711 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr );
1712 }
1713 // non-screen textures will never be filtered
1714 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1715 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1716
1717 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1718 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1719
1720 pfn_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1721 GL_TEXTURE_2D, text_name, 0);
1722
1723 if ( gl_checkFramebufferStatus() )
1724 {
1725 osd_printf_error("FBO error fbo texture - bail out\n");
1726 return -1;
1727 }
1728
1729 return 0;
1730 }
1731
texture_shader_create(const render_texinfo * texsource,ogl_texture_info * texture,uint32_t flags)1732 int renderer_ogl::texture_shader_create(const render_texinfo *texsource, ogl_texture_info *texture, uint32_t flags)
1733 {
1734 int uniform_location;
1735 int i;
1736 int surf_w_pow2 = get_valid_pow2_value (m_blit_dim.width(), texture->texpow2);
1737 int surf_h_pow2 = get_valid_pow2_value (m_blit_dim.height(), texture->texpow2);
1738
1739 assert ( texture->type==TEXTURE_TYPE_SHADER );
1740
1741 GL_CHECK_ERROR_QUIET();
1742
1743 if( m_glsl_program_num > 1 )
1744 {
1745 // multipass mode
1746 assert(m_usefbo);
1747
1748 // GL_TEXTURE3 GLSL Uniforms
1749 texture->mpass_dest_idx = 0;
1750 texture->mpass_textureunit[0] = GL_TEXTURE3;
1751 texture->mpass_textureunit[1] = GL_TEXTURE2;
1752 }
1753
1754 for(i=0; i<m_glsl_program_num; i++)
1755 {
1756 if ( i<=m_glsl_program_mb2sc )
1757 {
1758 m_glsl_program[i] = glsl_shader_get_program_mamebm(glsl_shader_feature, i);
1759 } else {
1760 m_glsl_program[i] = glsl_shader_get_program_scrn(i-1-m_glsl_program_mb2sc);
1761 }
1762 pfn_glUseProgramObjectARB(m_glsl_program[i]);
1763
1764 if ( i<=m_glsl_program_mb2sc )
1765 {
1766 // GL_TEXTURE0 GLSL Uniforms
1767 uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[i], "color_texture");
1768 pfn_glUniform1iARB(uniform_location, 0);
1769 GL_CHECK_ERROR_NORMAL();
1770 }
1771
1772 {
1773 GLfloat color_texture_sz[2] = { (GLfloat)texture->rawwidth, (GLfloat)texture->rawheight };
1774 uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[i], "color_texture_sz");
1775 pfn_glUniform2fvARB(uniform_location, 1, &(color_texture_sz[0]));
1776 GL_CHECK_ERROR_NORMAL();
1777 }
1778
1779 GLfloat color_texture_pow2_sz[2] = { (GLfloat)texture->rawwidth_create, (GLfloat)texture->rawheight_create };
1780 uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[i], "color_texture_pow2_sz");
1781 pfn_glUniform2fvARB(uniform_location, 1, &(color_texture_pow2_sz[0]));
1782 GL_CHECK_ERROR_NORMAL();
1783
1784 GLfloat screen_texture_sz[2] = { (GLfloat) m_blit_dim.width(), (GLfloat) m_blit_dim.height() };
1785 uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[i], "screen_texture_sz");
1786 pfn_glUniform2fvARB(uniform_location, 1, &(screen_texture_sz[0]));
1787 GL_CHECK_ERROR_NORMAL();
1788
1789 GLfloat screen_texture_pow2_sz[2] = { (GLfloat)surf_w_pow2, (GLfloat)surf_h_pow2 };
1790 uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[i], "screen_texture_pow2_sz");
1791 pfn_glUniform2fvARB(uniform_location, 1, &(screen_texture_pow2_sz[0]));
1792 GL_CHECK_ERROR_NORMAL();
1793 }
1794
1795 pfn_glUseProgramObjectARB(m_glsl_program[0]); // start with 1st shader
1796
1797 if( m_glsl_program_num > 1 )
1798 {
1799 // multipass mode
1800 // GL_TEXTURE2/GL_TEXTURE3
1801 pfn_glGenFramebuffers(2, (GLuint *)&texture->mpass_fbo_mamebm[0]);
1802 glGenTextures(2, (GLuint *)&texture->mpass_texture_mamebm[0]);
1803
1804 for (i=0; i<2; i++)
1805 {
1806 if ( texture_fbo_create(texture->mpass_textureunit[i],
1807 texture->mpass_texture_mamebm[i],
1808 texture->mpass_fbo_mamebm[i],
1809 texture->rawwidth_create, texture->rawheight_create) )
1810 {
1811 return -1;
1812 }
1813 }
1814
1815 pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1816
1817 osd_printf_verbose("GL texture: mpass mame-bmp 2x %dx%d (pow2 %dx%d)\n",
1818 texture->rawwidth, texture->rawheight, texture->rawwidth_create, texture->rawheight_create);
1819 }
1820
1821 if( m_glsl_program_num > 1 && m_glsl_program_mb2sc < m_glsl_program_num - 1 )
1822 {
1823 // multipass mode
1824 // GL_TEXTURE2/GL_TEXTURE3
1825 pfn_glGenFramebuffers(2, (GLuint *)&texture->mpass_fbo_scrn[0]);
1826 glGenTextures(2, (GLuint *)&texture->mpass_texture_scrn[0]);
1827
1828 for (i=0; i<2; i++)
1829 {
1830 if ( texture_fbo_create(texture->mpass_textureunit[i],
1831 texture->mpass_texture_scrn[i],
1832 texture->mpass_fbo_scrn[i],
1833 surf_w_pow2, surf_h_pow2) )
1834 {
1835 return -1;
1836 }
1837 }
1838
1839 osd_printf_verbose("GL texture: mpass screen-bmp 2x %dx%d (pow2 %dx%d)\n",
1840 m_width, m_height, surf_w_pow2, surf_h_pow2);
1841 }
1842
1843 // GL_TEXTURE0
1844 // get a name for this texture
1845 glGenTextures(1, (GLuint *)&texture->texture);
1846 pfn_glActiveTexture(GL_TEXTURE0);
1847 glBindTexture(GL_TEXTURE_2D, texture->texture);
1848
1849 glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->rawwidth_create);
1850
1851 uint32_t * dummy = nullptr;
1852 GLint _width, _height;
1853 if ( gl_texture_check_size(GL_TEXTURE_2D, 0, GL_RGBA8,
1854 texture->rawwidth_create, texture->rawheight_create,
1855 0,
1856 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
1857 &_width, &_height, 1) )
1858 {
1859 osd_printf_error("cannot create bitmap texture, req: %dx%d, avail: %dx%d - bail out\n",
1860 texture->rawwidth_create, texture->rawheight_create, (int)_width, (int)_height);
1861 return -1;
1862 }
1863
1864 dummy = (uint32_t *) malloc(texture->rawwidth_create * texture->rawheight_create * sizeof(uint32_t));
1865 memset(dummy, 0, texture->rawwidth_create * texture->rawheight_create * sizeof(uint32_t));
1866 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
1867 texture->rawwidth_create, texture->rawheight_create,
1868 0,
1869 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, dummy);
1870 glFinish(); // should not be necessary, .. but make sure we won't access the memory after free
1871 free(dummy);
1872
1873 if ((PRIMFLAG_GET_SCREENTEX(flags)) && video_config.filter)
1874 {
1875 assert( glsl_shader_feature == GLSL_SHADER_FEAT_PLAIN );
1876
1877 // screen textures get the user's choice of filtering
1878 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1879 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1880 }
1881 else
1882 {
1883 // non-screen textures will never be filtered
1884 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1885 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1886 }
1887
1888 // set wrapping mode appropriately
1889 if (texture->flags & PRIMFLAG_TEXWRAP_MASK)
1890 {
1891 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1892 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1893 }
1894 else
1895 {
1896 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1897 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1898 }
1899
1900 GL_CHECK_ERROR_NORMAL();
1901
1902 return 0;
1903 }
1904
texture_create(const render_texinfo * texsource,uint32_t flags)1905 ogl_texture_info *renderer_ogl::texture_create(const render_texinfo *texsource, uint32_t flags)
1906 {
1907 ogl_texture_info *texture;
1908
1909 // allocate a new texture
1910 texture = new ogl_texture_info;
1911
1912 // fill in the core data
1913 texture->hash = texture_compute_hash(texsource, flags);
1914 texture->flags = flags;
1915 texture->texinfo = *texsource;
1916 texture->texinfo.seqid = -1; // force set data
1917 if (PRIMFLAG_GET_SCREENTEX(flags))
1918 {
1919 auto win = assert_window();
1920 texture->xprescale = win->prescale();
1921 texture->yprescale = win->prescale();
1922 }
1923 else
1924 {
1925 texture->xprescale = 1;
1926 texture->yprescale = 1;
1927 }
1928
1929 // set the texture_format
1930 //
1931 // src/emu/validity.c:validate_display() states,
1932 // an emulated driver can only produce
1933 // BITMAP_FORMAT_IND16 and BITMAP_FORMAT_RGB32
1934 // where only the first original paletted.
1935 //
1936 // other paletted formats, i.e.:
1937 // SDL_TEXFORMAT_RGB32_PALETTED, SDL_TEXFORMAT_RGB15_PALETTED and SDL_TEXFORMAT_YUY16_PALETTED
1938 // add features like brightness etc by the mame core
1939 //
1940 // all palette lookup may be implemented using shaders later on ..
1941 // that's why we keep the EQUAL flag TRUE, for all original true color bitmaps.
1942 //
1943 switch (PRIMFLAG_GET_TEXFORMAT(flags))
1944 {
1945 case TEXFORMAT_ARGB32:
1946 texture->format = SDL_TEXFORMAT_ARGB32;
1947 break;
1948 case TEXFORMAT_RGB32:
1949 if (texsource->palette != nullptr)
1950 texture->format = SDL_TEXFORMAT_RGB32_PALETTED;
1951 else
1952 texture->format = SDL_TEXFORMAT_RGB32;
1953 break;
1954 case TEXFORMAT_PALETTE16:
1955 texture->format = SDL_TEXFORMAT_PALETTE16;
1956 break;
1957 case TEXFORMAT_YUY16:
1958 if (texsource->palette != nullptr)
1959 texture->format = SDL_TEXFORMAT_YUY16_PALETTED;
1960 else
1961 texture->format = SDL_TEXFORMAT_YUY16;
1962 break;
1963
1964 default:
1965 osd_printf_error("Unknown textureformat %d\n", PRIMFLAG_GET_TEXFORMAT(flags));
1966 }
1967
1968 // compute the size
1969 texture_compute_size_type(texsource, texture, flags);
1970
1971 texture->pbo=0;
1972
1973 if ( texture->type != TEXTURE_TYPE_SHADER && m_useglsl)
1974 {
1975 pfn_glUseProgramObjectARB(0); // back to fixed function pipeline
1976 }
1977
1978 if ( texture->type==TEXTURE_TYPE_SHADER )
1979 {
1980 if ( texture_shader_create(texsource, texture, flags) )
1981 {
1982 delete texture;
1983 return nullptr;
1984 }
1985 }
1986 else
1987 {
1988 // get a name for this texture
1989 glGenTextures(1, (GLuint *)&texture->texture);
1990
1991 glEnable(texture->texTarget);
1992
1993 // make sure we're operating on *this* texture
1994 glBindTexture(texture->texTarget, texture->texture);
1995
1996 // this doesn't actually upload, it just sets up the PBO's parameters
1997 glTexImage2D(texture->texTarget, 0, GL_RGBA8,
1998 texture->rawwidth_create, texture->rawheight_create,
1999 texture->borderpix ? 1 : 0,
2000 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
2001
2002 if ((PRIMFLAG_GET_SCREENTEX(flags)) && video_config.filter)
2003 {
2004 // screen textures get the user's choice of filtering
2005 glTexParameteri(texture->texTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2006 glTexParameteri(texture->texTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2007 }
2008 else
2009 {
2010 // non-screen textures will never be filtered
2011 glTexParameteri(texture->texTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2012 glTexParameteri(texture->texTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2013 }
2014
2015 if( texture->texTarget==GL_TEXTURE_RECTANGLE_ARB )
2016 {
2017 // texture rectangles can't wrap
2018 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2019 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2020 } else {
2021 // set wrapping mode appropriately
2022 if (texture->flags & PRIMFLAG_TEXWRAP_MASK)
2023 {
2024 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
2025 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
2026 }
2027 else
2028 {
2029 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2030 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2031 }
2032 }
2033 }
2034
2035 if ( texture->type == TEXTURE_TYPE_DYNAMIC )
2036 {
2037 assert(m_usepbo);
2038
2039 // create the PBO
2040 pfn_glGenBuffers(1, (GLuint *)&texture->pbo);
2041
2042 pfn_glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, texture->pbo);
2043
2044 // set up the PBO dimension, ..
2045 pfn_glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB,
2046 texture->rawwidth * texture->rawheight * sizeof(uint32_t),
2047 nullptr, GL_STREAM_DRAW);
2048 }
2049
2050 if ( !texture->nocopy && texture->type!=TEXTURE_TYPE_DYNAMIC )
2051 {
2052 texture->data = (uint32_t *) malloc(texture->rawwidth* texture->rawheight * sizeof(uint32_t));
2053 texture->data_own=true;
2054 }
2055
2056 // add us to the texture list
2057 if (m_texhash[texture->hash] == nullptr)
2058 m_texhash[texture->hash] = texture;
2059 else
2060 {
2061 int i;
2062 for (i = HASH_SIZE; i < HASH_SIZE + OVERFLOW_SIZE; i++)
2063 if (m_texhash[i] == nullptr)
2064 {
2065 m_texhash[i] = texture;
2066 break;
2067 }
2068 if ((HASH_SIZE + OVERFLOW_SIZE) <= i)
2069 throw emu_fatalerror("renderer_ogl::texture_create: texture hash exhausted ...");
2070 }
2071
2072 if (m_usevbo)
2073 {
2074 // Generate And Bind The Texture Coordinate Buffer
2075 pfn_glGenBuffers( 1, &(texture->texCoordBufferName) );
2076 pfn_glBindBuffer( GL_ARRAY_BUFFER_ARB, texture->texCoordBufferName );
2077 // Load The Data
2078 pfn_glBufferData( GL_ARRAY_BUFFER_ARB, 4*2*sizeof(GLfloat), texture->texCoord, GL_STREAM_DRAW );
2079 glTexCoordPointer( 2, GL_FLOAT, 0, (char *) nullptr ); // we are using ARB VBO buffers
2080 }
2081 else
2082 {
2083 glTexCoordPointer(2, GL_FLOAT, 0, texture->texCoord);
2084 }
2085
2086 return texture;
2087 }
2088
2089 //============================================================
2090 // copyline_palette16
2091 //============================================================
2092
copyline_palette16(uint32_t * dst,const uint16_t * src,int width,const rgb_t * palette,int xborderpix,int xprescale)2093 static inline void copyline_palette16(uint32_t *dst, const uint16_t *src, int width, const rgb_t *palette, int xborderpix, int xprescale)
2094 {
2095 int x;
2096
2097 assert(xborderpix == 0 || xborderpix == 1);
2098 if (xborderpix)
2099 *dst++ = 0xff000000 | palette[*src];
2100 for (x = 0; x < width; x++)
2101 {
2102 int srcpix = *src++;
2103 uint32_t dstval = 0xff000000 | palette[srcpix];
2104 for (int x2 = 0; x2 < xprescale; x2++)
2105 *dst++ = dstval;
2106 }
2107 if (xborderpix)
2108 *dst++ = 0xff000000 | palette[*--src];
2109 }
2110
2111
2112
2113 //============================================================
2114 // copyline_rgb32
2115 //============================================================
2116
copyline_rgb32(uint32_t * dst,const uint32_t * src,int width,const rgb_t * palette,int xborderpix,int xprescale)2117 static inline void copyline_rgb32(uint32_t *dst, const uint32_t *src, int width, const rgb_t *palette, int xborderpix, int xprescale)
2118 {
2119 int x;
2120
2121 assert(xborderpix == 0 || xborderpix == 1);
2122
2123 // palette (really RGB map) case
2124 if (palette != nullptr)
2125 {
2126 if (xborderpix)
2127 {
2128 rgb_t srcpix = *src;
2129 *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2130 }
2131 for (x = 0; x < width; x++)
2132 {
2133 rgb_t srcpix = *src++;
2134 uint32_t dstval = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2135 for (int x2 = 0; x2 < xprescale; x2++)
2136 *dst++ = dstval;
2137 }
2138 if (xborderpix)
2139 {
2140 rgb_t srcpix = *--src;
2141 *dst++ = 0xff000000 | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2142 }
2143 }
2144
2145 // direct case
2146 else
2147 {
2148 if (xborderpix)
2149 *dst++ = 0xff000000 | *src;
2150 for (x = 0; x < width; x++)
2151 {
2152 rgb_t srcpix = *src++;
2153 uint32_t dstval = 0xff000000 | srcpix;
2154 for (int x2 = 0; x2 < xprescale; x2++)
2155 *dst++ = dstval;
2156 }
2157 if (xborderpix)
2158 *dst++ = 0xff000000 | *--src;
2159 }
2160 }
2161
2162 //============================================================
2163 // copyline_argb32
2164 //============================================================
2165
copyline_argb32(uint32_t * dst,const uint32_t * src,int width,const rgb_t * palette,int xborderpix,int xprescale)2166 static inline void copyline_argb32(uint32_t *dst, const uint32_t *src, int width, const rgb_t *palette, int xborderpix, int xprescale)
2167 {
2168 int x;
2169
2170 assert(xborderpix == 0 || xborderpix == 1);
2171
2172 // palette (really RGB map) case
2173 if (palette != nullptr)
2174 {
2175 if (xborderpix)
2176 {
2177 rgb_t srcpix = *src;
2178 *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2179 }
2180 for (x = 0; x < width; x++)
2181 {
2182 rgb_t srcpix = *src++;
2183 uint32_t dstval = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2184 for (int x2 = 0; x2 < xprescale; x2++)
2185 *dst++ = dstval;
2186 }
2187 if (xborderpix)
2188 {
2189 rgb_t srcpix = *--src;
2190 *dst++ = (srcpix & 0xff000000) | palette[0x200 + srcpix.r()] | palette[0x100 + srcpix.g()] | palette[srcpix.b()];
2191 }
2192 }
2193
2194 // direct case
2195 else
2196 {
2197 if (xborderpix)
2198 *dst++ = *src;
2199 for (x = 0; x < width; x++)
2200 {
2201 rgb_t srcpix = *src++;
2202 for (int x2 = 0; x2 < xprescale; x2++)
2203 *dst++ = srcpix;
2204 }
2205 if (xborderpix)
2206 *dst++ = *--src;
2207 }
2208 }
2209
ycc_to_rgb(uint8_t y,uint8_t cb,uint8_t cr)2210 static inline uint32_t ycc_to_rgb(uint8_t y, uint8_t cb, uint8_t cr)
2211 {
2212 /* original equations:
2213
2214 C = Y - 16
2215 D = Cb - 128
2216 E = Cr - 128
2217
2218 R = clip(( 298 * C + 409 * E + 128) >> 8)
2219 G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8)
2220 B = clip(( 298 * C + 516 * D + 128) >> 8)
2221
2222 R = clip(( 298 * (Y - 16) + 409 * (Cr - 128) + 128) >> 8)
2223 G = clip(( 298 * (Y - 16) - 100 * (Cb - 128) - 208 * (Cr - 128) + 128) >> 8)
2224 B = clip(( 298 * (Y - 16) + 516 * (Cb - 128) + 128) >> 8)
2225
2226 R = clip(( 298 * Y - 298 * 16 + 409 * Cr - 409 * 128 + 128) >> 8)
2227 G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8)
2228 B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128 + 128) >> 8)
2229
2230 R = clip(( 298 * Y - 298 * 16 + 409 * Cr - 409 * 128 + 128) >> 8)
2231 G = clip(( 298 * Y - 298 * 16 - 100 * Cb + 100 * 128 - 208 * Cr + 208 * 128 + 128) >> 8)
2232 B = clip(( 298 * Y - 298 * 16 + 516 * Cb - 516 * 128 + 128) >> 8)
2233 */
2234 int r, g, b, common;
2235
2236 common = 298 * y - 298 * 16;
2237 r = (common + 409 * cr - 409 * 128 + 128) >> 8;
2238 g = (common - 100 * cb + 100 * 128 - 208 * cr + 208 * 128 + 128) >> 8;
2239 b = (common + 516 * cb - 516 * 128 + 128) >> 8;
2240
2241 if (r < 0) r = 0;
2242 else if (r > 255) r = 255;
2243 if (g < 0) g = 0;
2244 else if (g > 255) g = 255;
2245 if (b < 0) b = 0;
2246 else if (b > 255) b = 255;
2247
2248 return rgb_t(0xff, r, g, b);
2249 }
2250
2251 //============================================================
2252 // copyline_yuy16_to_argb
2253 //============================================================
2254
copyline_yuy16_to_argb(uint32_t * dst,const uint16_t * src,int width,const rgb_t * palette,int xborderpix,int xprescale)2255 static inline void copyline_yuy16_to_argb(uint32_t *dst, const uint16_t *src, int width, const rgb_t *palette, int xborderpix, int xprescale)
2256 {
2257 int x;
2258
2259 assert(xborderpix == 0 || xborderpix == 2);
2260 assert(width % 2 == 0);
2261
2262 // palette (really RGB map) case
2263 if (palette != nullptr)
2264 {
2265 if (xborderpix)
2266 {
2267 uint16_t srcpix0 = src[0];
2268 uint16_t srcpix1 = src[1];
2269 uint8_t cb = srcpix0 & 0xff;
2270 uint8_t cr = srcpix1 & 0xff;
2271 *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr);
2272 *dst++ = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr);
2273 }
2274 for (x = 0; x < width / 2; x++)
2275 {
2276 uint16_t srcpix0 = *src++;
2277 uint16_t srcpix1 = *src++;
2278 uint8_t cb = srcpix0 & 0xff;
2279 uint8_t cr = srcpix1 & 0xff;
2280 uint32_t dstval0 = ycc_to_rgb(palette[0x000 + (srcpix0 >> 8)], cb, cr);
2281 uint32_t dstval1 = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr);
2282 for (int x2 = 0; x2 < xprescale; x2++)
2283 *dst++ = dstval0;
2284 for (int x2 = 0; x2 < xprescale; x2++)
2285 *dst++ = dstval1;
2286 }
2287 if (xborderpix)
2288 {
2289 uint16_t srcpix1 = *--src;
2290 uint16_t srcpix0 = *--src;
2291 uint8_t cb = srcpix0 & 0xff;
2292 uint8_t cr = srcpix1 & 0xff;
2293 *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr);
2294 *dst++ = ycc_to_rgb(palette[0x000 + (srcpix1 >> 8)], cb, cr);
2295 }
2296 }
2297
2298 // direct case
2299 else
2300 {
2301 if (xborderpix)
2302 {
2303 uint16_t srcpix0 = src[0];
2304 uint16_t srcpix1 = src[1];
2305 uint8_t cb = srcpix0 & 0xff;
2306 uint8_t cr = srcpix1 & 0xff;
2307 *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr);
2308 *dst++ = ycc_to_rgb(srcpix0 >> 8, cb, cr);
2309 }
2310 for (x = 0; x < width; x += 2)
2311 {
2312 uint16_t srcpix0 = *src++;
2313 uint16_t srcpix1 = *src++;
2314 uint8_t cb = srcpix0 & 0xff;
2315 uint8_t cr = srcpix1 & 0xff;
2316 uint32_t dstval0 = ycc_to_rgb(srcpix0 >> 8, cb, cr);
2317 uint32_t dstval1 = ycc_to_rgb(srcpix1 >> 8, cb, cr);
2318 for (int x2 = 0; x2 < xprescale; x2++)
2319 *dst++ = dstval0;
2320 for (int x2 = 0; x2 < xprescale; x2++)
2321 *dst++ = dstval1;
2322 }
2323 if (xborderpix)
2324 {
2325 uint16_t srcpix1 = *--src;
2326 uint16_t srcpix0 = *--src;
2327 uint8_t cb = srcpix0 & 0xff;
2328 uint8_t cr = srcpix1 & 0xff;
2329 *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr);
2330 *dst++ = ycc_to_rgb(srcpix1 >> 8, cb, cr);
2331 }
2332 }
2333 }
2334
2335 //============================================================
2336 // texture_set_data
2337 //============================================================
2338
texture_set_data(ogl_texture_info * texture,const render_texinfo * texsource,uint32_t flags)2339 static void texture_set_data(ogl_texture_info *texture, const render_texinfo *texsource, uint32_t flags)
2340 {
2341 if ( texture->type == TEXTURE_TYPE_DYNAMIC )
2342 {
2343 assert(texture->pbo);
2344 assert(!texture->nocopy);
2345
2346 texture->data = (uint32_t *) pfn_glMapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY);
2347 }
2348
2349 // note that nocopy and borderpix are mutually exclusive, IOW
2350 // they cannot be both true, thus this cannot lead to the
2351 // borderpix code below writing to texsource->base .
2352 if (texture->nocopy)
2353 {
2354 texture->data = (uint32_t *) texsource->base;
2355 }
2356
2357 // always fill non-wrapping textures with an extra pixel on the top
2358 if (texture->borderpix)
2359 {
2360 memset(texture->data, 0,
2361 (texsource->width * texture->xprescale + 2) * sizeof(uint32_t));
2362 }
2363
2364 // when necessary copy (and convert) the data
2365 if (!texture->nocopy)
2366 {
2367 int y, y2;
2368 uint8_t *dst;
2369
2370 for (y = 0; y < texsource->height; y++)
2371 {
2372 for (y2 = 0; y2 < texture->yprescale; y2++)
2373 {
2374 dst = (uint8_t *)(texture->data + (y * texture->yprescale + texture->borderpix + y2) * texture->rawwidth);
2375
2376 switch (PRIMFLAG_GET_TEXFORMAT(flags))
2377 {
2378 case TEXFORMAT_PALETTE16:
2379 copyline_palette16((uint32_t *)dst, (uint16_t *)texsource->base + y * texsource->rowpixels, texsource->width, texsource->palette, texture->borderpix, texture->xprescale);
2380 break;
2381
2382 case TEXFORMAT_RGB32:
2383 copyline_rgb32((uint32_t *)dst, (uint32_t *)texsource->base + y * texsource->rowpixels, texsource->width, texsource->palette, texture->borderpix, texture->xprescale);
2384 break;
2385
2386 case TEXFORMAT_ARGB32:
2387 copyline_argb32((uint32_t *)dst, (uint32_t *)texsource->base + y * texsource->rowpixels, texsource->width, texsource->palette, texture->borderpix, texture->xprescale);
2388 break;
2389
2390 case TEXFORMAT_YUY16:
2391 copyline_yuy16_to_argb((uint32_t *)dst, (uint16_t *)texsource->base + y * texsource->rowpixels, texsource->width, texsource->palette, texture->borderpix, texture->xprescale);
2392 break;
2393
2394 default:
2395 osd_printf_error("Unknown texture blendmode=%d format=%d\n", PRIMFLAG_GET_BLENDMODE(flags), PRIMFLAG_GET_TEXFORMAT(flags));
2396 break;
2397 }
2398 }
2399 }
2400 }
2401
2402 // always fill non-wrapping textures with an extra pixel on the bottom
2403 if (texture->borderpix)
2404 {
2405 memset((uint8_t *)texture->data +
2406 (texsource->height + 1) * texture->rawwidth * sizeof(uint32_t),
2407 0,
2408 (texsource->width * texture->xprescale + 2) * sizeof(uint32_t));
2409 }
2410
2411 if ( texture->type == TEXTURE_TYPE_SHADER )
2412 {
2413 pfn_glActiveTexture(GL_TEXTURE0);
2414 glBindTexture(texture->texTarget, texture->texture);
2415
2416 if (texture->nocopy)
2417 glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->texinfo.rowpixels);
2418 else
2419 glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->rawwidth);
2420
2421 // and upload the image
2422 glTexSubImage2D(texture->texTarget, 0, 0, 0, texture->rawwidth, texture->rawheight,
2423 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, texture->data);
2424 }
2425 else if ( texture->type == TEXTURE_TYPE_DYNAMIC )
2426 {
2427 glBindTexture(texture->texTarget, texture->texture);
2428
2429 glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->rawwidth);
2430
2431 // unmap the buffer from the CPU space so it can DMA
2432 pfn_glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER_ARB);
2433
2434 // kick off the DMA
2435 glTexSubImage2D(texture->texTarget, 0, 0, 0, texture->rawwidth, texture->rawheight,
2436 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
2437 }
2438 else
2439 {
2440 glBindTexture(texture->texTarget, texture->texture);
2441
2442 // give the card a hint
2443 if (texture->nocopy)
2444 glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->texinfo.rowpixels);
2445 else
2446 glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->rawwidth);
2447
2448 // and upload the image
2449 glTexSubImage2D(texture->texTarget, 0, 0, 0, texture->rawwidth, texture->rawheight,
2450 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, texture->data);
2451 }
2452 }
2453
2454 //============================================================
2455 // texture_find
2456 //============================================================
2457
compare_texture_primitive(const ogl_texture_info * texture,const render_primitive * prim)2458 static int compare_texture_primitive(const ogl_texture_info *texture, const render_primitive *prim)
2459 {
2460 if (texture->texinfo.base == prim->texture.base &&
2461 texture->texinfo.width == prim->texture.width &&
2462 texture->texinfo.height == prim->texture.height &&
2463 texture->texinfo.rowpixels == prim->texture.rowpixels &&
2464 texture->texinfo.palette == prim->texture.palette &&
2465 ((texture->flags ^ prim->flags) & (PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) == 0)
2466 return 1;
2467 else
2468 return 0;
2469 }
2470
texture_find(const render_primitive * prim)2471 ogl_texture_info *renderer_ogl::texture_find(const render_primitive *prim)
2472 {
2473 HashT texhash = texture_compute_hash(&prim->texture, prim->flags);
2474 ogl_texture_info *texture;
2475
2476 texture = m_texhash[texhash];
2477 if (texture != nullptr)
2478 {
2479 int i;
2480 if (compare_texture_primitive(texture, prim))
2481 return texture;
2482 for (i=HASH_SIZE; i<HASH_SIZE + OVERFLOW_SIZE; i++)
2483 {
2484 texture = m_texhash[i];
2485 if (texture != nullptr && compare_texture_primitive(texture, prim))
2486 return texture;
2487 }
2488 }
2489 return nullptr;
2490 }
2491
2492 //============================================================
2493 // texture_update
2494 //============================================================
2495
texture_coord_update(ogl_texture_info * texture,const render_primitive * prim,int shaderIdx)2496 void renderer_ogl::texture_coord_update(ogl_texture_info *texture, const render_primitive *prim, int shaderIdx)
2497 {
2498 float ustart = 0.0f, ustop = 0.0f; // beginning/ending U coordinates
2499 float vstart = 0.0f, vstop = 0.0f; // beginning/ending V coordinates
2500 float du, dv;
2501
2502 if ( texture->type != TEXTURE_TYPE_SHADER ||
2503 ( texture->type == TEXTURE_TYPE_SHADER && shaderIdx<=m_glsl_program_mb2sc ) )
2504 {
2505 // compute the U/V scale factors
2506 if (texture->borderpix)
2507 {
2508 int unscaledwidth = (texture->rawwidth_create-2) / texture->xprescale + 2;
2509 int unscaledheight = (texture->rawheight_create-2) / texture->yprescale + 2;
2510 ustart = 1.0f / (float)(unscaledwidth);
2511 ustop = (float)(prim->texture.width + 1) / (float)(unscaledwidth);
2512 vstart = 1.0f / (float)(unscaledheight);
2513 vstop = (float)(prim->texture.height + 1) / (float)(unscaledheight);
2514 }
2515 else
2516 {
2517 ustop = (float)(prim->texture.width*texture->xprescale) / (float)texture->rawwidth_create;
2518 vstop = (float)(prim->texture.height*texture->yprescale) / (float)texture->rawheight_create;
2519 }
2520 }
2521 else if ( texture->type == TEXTURE_TYPE_SHADER && shaderIdx>m_glsl_program_mb2sc )
2522 {
2523 int surf_w_pow2 = get_valid_pow2_value (m_width, texture->texpow2);
2524 int surf_h_pow2 = get_valid_pow2_value (m_height, texture->texpow2);
2525
2526 ustop = (float)(m_width) / (float)surf_w_pow2;
2527 vstop = (float)(m_height) / (float)surf_h_pow2;
2528
2529 }
2530 else
2531 {
2532 assert(0); // ??
2533 }
2534
2535 du = ustop - ustart;
2536 dv = vstop - vstart;
2537
2538 if ( texture->texTarget == GL_TEXTURE_RECTANGLE_ARB )
2539 {
2540 // texture coordinates for TEXTURE_RECTANGLE are 0,0 -> w,h
2541 // rather than 0,0 -> 1,1 as with normal OpenGL texturing
2542 du *= (float)texture->rawwidth;
2543 dv *= (float)texture->rawheight;
2544 }
2545
2546 if ( texture->type == TEXTURE_TYPE_SHADER && shaderIdx!=m_glsl_program_mb2sc )
2547 {
2548 // 1:1 tex coord CCW (0/0) (1/0) (1/1) (0/1)
2549 // we must go CW here due to the mame bitmap order
2550 texture->texCoord[0]=ustart + du * 0.0f;
2551 texture->texCoord[1]=vstart + dv * 1.0f;
2552 texture->texCoord[2]=ustart + du * 1.0f;
2553 texture->texCoord[3]=vstart + dv * 1.0f;
2554 texture->texCoord[4]=ustart + du * 1.0f;
2555 texture->texCoord[5]=vstart + dv * 0.0f;
2556 texture->texCoord[6]=ustart + du * 0.0f;
2557 texture->texCoord[7]=vstart + dv * 0.0f;
2558 }
2559 else
2560 {
2561 // transformation: mamebm -> scrn
2562 texture->texCoord[0]=ustart + du * prim->texcoords.tl.u;
2563 texture->texCoord[1]=vstart + dv * prim->texcoords.tl.v;
2564 texture->texCoord[2]=ustart + du * prim->texcoords.tr.u;
2565 texture->texCoord[3]=vstart + dv * prim->texcoords.tr.v;
2566 texture->texCoord[4]=ustart + du * prim->texcoords.br.u;
2567 texture->texCoord[5]=vstart + dv * prim->texcoords.br.v;
2568 texture->texCoord[6]=ustart + du * prim->texcoords.bl.u;
2569 texture->texCoord[7]=vstart + dv * prim->texcoords.bl.v;
2570 }
2571 }
2572
texture_mpass_flip(ogl_texture_info * texture,int shaderIdx)2573 void renderer_ogl::texture_mpass_flip(ogl_texture_info *texture, int shaderIdx)
2574 {
2575 uint32_t mpass_src_idx = texture->mpass_dest_idx;
2576
2577 texture->mpass_dest_idx = (mpass_src_idx+1) % 2;
2578
2579 if ( shaderIdx>0 )
2580 {
2581 int uniform_location;
2582 uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[shaderIdx], "mpass_texture");
2583 pfn_glUniform1iARB(uniform_location, texture->mpass_textureunit[mpass_src_idx]-GL_TEXTURE0);
2584 GL_CHECK_ERROR_NORMAL();
2585 }
2586
2587 pfn_glActiveTexture(texture->mpass_textureunit[mpass_src_idx]);
2588 if ( shaderIdx<=m_glsl_program_mb2sc )
2589 {
2590 glBindTexture(texture->texTarget, texture->mpass_texture_mamebm[mpass_src_idx]);
2591 }
2592 else
2593 {
2594 glBindTexture(texture->texTarget, texture->mpass_texture_scrn[mpass_src_idx]);
2595 }
2596 pfn_glActiveTexture(texture->mpass_textureunit[texture->mpass_dest_idx]);
2597 glBindTexture(texture->texTarget, 0);
2598
2599 pfn_glActiveTexture(texture->mpass_textureunit[texture->mpass_dest_idx]);
2600
2601 if ( shaderIdx<m_glsl_program_num-1 )
2602 {
2603 if ( shaderIdx>=m_glsl_program_mb2sc )
2604 {
2605 glBindTexture(texture->texTarget, texture->mpass_texture_scrn[texture->mpass_dest_idx]);
2606 pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, texture->mpass_fbo_scrn[texture->mpass_dest_idx]);
2607 }
2608 else
2609 {
2610 glBindTexture(texture->texTarget, texture->mpass_texture_mamebm[texture->mpass_dest_idx]);
2611 pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, texture->mpass_fbo_mamebm[texture->mpass_dest_idx]);
2612 }
2613
2614 if ( shaderIdx==0 )
2615 {
2616 glPushAttrib(GL_VIEWPORT_BIT);
2617 GL_CHECK_ERROR_NORMAL();
2618 glViewport(0.0, 0.0, (GLsizei)texture->rawwidth, (GLsizei)texture->rawheight);
2619 }
2620
2621 if ( shaderIdx==m_glsl_program_mb2sc )
2622 {
2623 assert ( m_glsl_program_mb2sc < m_glsl_program_num-1 );
2624 glPopAttrib(); // glViewport(0.0, 0.0, (GLsizei)window().width, (GLsizei)window().height)
2625 GL_CHECK_ERROR_NORMAL();
2626 }
2627 glClear(GL_COLOR_BUFFER_BIT); // make sure the whole texture is redrawn ..
2628 }
2629 else
2630 {
2631 glBindTexture(texture->texTarget, 0);
2632 pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
2633
2634 if ( m_glsl_program_mb2sc == m_glsl_program_num-1 )
2635 {
2636 glPopAttrib(); // glViewport(0.0, 0.0, (GLsizei)window().width, (GLsizei)window().height)
2637 GL_CHECK_ERROR_NORMAL();
2638 }
2639
2640 pfn_glActiveTexture(GL_TEXTURE0);
2641 glBindTexture(texture->texTarget, 0);
2642 }
2643 }
2644
texture_shader_update(ogl_texture_info * texture,render_container * container,int shaderIdx)2645 void renderer_ogl::texture_shader_update(ogl_texture_info *texture, render_container *container, int shaderIdx)
2646 {
2647 int uniform_location;
2648 GLfloat vid_attributes[4];
2649
2650 if (container!=nullptr)
2651 {
2652 render_container::user_settings settings;
2653 container->get_user_settings(settings);
2654 /* FIXME: the code below is in just for illustration issue on
2655 * how to set shader variables. gamma, contrast and brightness are
2656 * handled already by the core
2657 */
2658 vid_attributes[0] = settings.m_gamma;
2659 vid_attributes[1] = settings.m_contrast;
2660 vid_attributes[2] = settings.m_brightness;
2661 vid_attributes[3] = 0.0f;
2662 uniform_location = pfn_glGetUniformLocationARB(m_glsl_program[shaderIdx], "vid_attributes");
2663 pfn_glUniform4fvARB(uniform_location, 1, &(vid_attributes[shaderIdx]));
2664 if ( GL_CHECK_ERROR_QUIET() ) {
2665 osd_printf_verbose("GLSL: could not set 'vid_attributes' for shader prog idx %d\n", shaderIdx);
2666 }
2667 }
2668 }
2669
texture_update(const render_primitive * prim,int shaderIdx)2670 ogl_texture_info * renderer_ogl::texture_update(const render_primitive *prim, int shaderIdx)
2671 {
2672 ogl_texture_info *texture = texture_find(prim);
2673 int texBound = 0;
2674
2675 // if we didn't find one, create a new texture
2676 if (texture == nullptr && prim->texture.base != nullptr)
2677 {
2678 texture = texture_create(&prim->texture, prim->flags);
2679 }
2680 else if (texture != nullptr)
2681 {
2682 if ( texture->type == TEXTURE_TYPE_SHADER )
2683 {
2684 pfn_glUseProgramObjectARB(m_glsl_program[shaderIdx]); // back to our shader
2685 }
2686 else if ( texture->type == TEXTURE_TYPE_DYNAMIC )
2687 {
2688 assert ( m_usepbo ) ;
2689 pfn_glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, texture->pbo);
2690 glEnable(texture->texTarget);
2691 }
2692 else
2693 {
2694 glEnable(texture->texTarget);
2695 }
2696 }
2697
2698 if (texture != nullptr)
2699 {
2700 if ( texture->type == TEXTURE_TYPE_SHADER )
2701 {
2702 texture_shader_update(texture, prim->container, shaderIdx);
2703 if ( m_glsl_program_num>1 )
2704 {
2705 texture_mpass_flip(texture, shaderIdx);
2706 }
2707 }
2708
2709 if ( shaderIdx==0 ) // redundant for subsequent multipass shader
2710 {
2711 if (prim->texture.base != nullptr && texture->texinfo.seqid != prim->texture.seqid)
2712 {
2713 texture->texinfo.seqid = prim->texture.seqid;
2714
2715 // if we found it, but with a different seqid, copy the data
2716 texture_set_data(texture, &prim->texture, prim->flags);
2717 texBound=1;
2718 }
2719 }
2720
2721 if (!texBound) {
2722 glBindTexture(texture->texTarget, texture->texture);
2723 }
2724 texture_coord_update(texture, prim, shaderIdx);
2725
2726 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2727 if(m_usevbo)
2728 {
2729 pfn_glBindBuffer( GL_ARRAY_BUFFER_ARB, texture->texCoordBufferName );
2730 // Load The Data
2731 pfn_glBufferSubData( GL_ARRAY_BUFFER_ARB, 0, 4*2*sizeof(GLfloat), texture->texCoord );
2732 glTexCoordPointer( 2, GL_FLOAT, 0, (char *) nullptr ); // we are using ARB VBO buffers
2733 }
2734 else
2735 {
2736 glTexCoordPointer(2, GL_FLOAT, 0, texture->texCoord);
2737 }
2738 }
2739
2740 return texture;
2741 }
2742
texture_disable(ogl_texture_info * texture)2743 void renderer_ogl::texture_disable(ogl_texture_info * texture)
2744 {
2745 if ( texture->type == TEXTURE_TYPE_SHADER )
2746 {
2747 assert ( m_useglsl );
2748 pfn_glUseProgramObjectARB(0); // back to fixed function pipeline
2749 } else if ( texture->type == TEXTURE_TYPE_DYNAMIC )
2750 {
2751 pfn_glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2752 glDisable(texture->texTarget);
2753 } else {
2754 glDisable(texture->texTarget);
2755 }
2756 }
2757
texture_all_disable()2758 void renderer_ogl::texture_all_disable()
2759 {
2760 if ( m_useglsl )
2761 {
2762 pfn_glUseProgramObjectARB(0); // back to fixed function pipeline
2763
2764 pfn_glActiveTexture(GL_TEXTURE3);
2765 glBindTexture(GL_TEXTURE_2D, 0);
2766 if ( m_usefbo ) pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
2767 pfn_glActiveTexture(GL_TEXTURE2);
2768 glBindTexture(GL_TEXTURE_2D, 0);
2769 if ( m_usefbo ) pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
2770 pfn_glActiveTexture(GL_TEXTURE1);
2771 glBindTexture(GL_TEXTURE_2D, 0);
2772 if ( m_usefbo ) pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
2773 pfn_glActiveTexture(GL_TEXTURE0);
2774 glBindTexture(GL_TEXTURE_2D, 0);
2775 if ( m_usefbo ) pfn_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
2776 }
2777 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
2778
2779 if(m_usetexturerect)
2780 {
2781 glDisable(GL_TEXTURE_RECTANGLE_ARB);
2782 }
2783 glDisable(GL_TEXTURE_2D);
2784
2785 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
2786 if(m_usevbo)
2787 {
2788 pfn_glBindBuffer( GL_ARRAY_BUFFER_ARB, 0); // unbind ..
2789 }
2790 if ( m_usepbo )
2791 {
2792 pfn_glBindBuffer( GL_PIXEL_UNPACK_BUFFER_ARB, 0);
2793 }
2794 }
2795