1 /*****************************************************************************\
2      Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3                 This file is licensed under the Snes9x License.
4    For further information, consult the LICENSE file in the root directory.
5 \*****************************************************************************/
6 
7 /***********************************************************************************
8   SNES9X for Mac OS (c) Copyright John Stiles
9 
10   Snes9x for Mac OS X
11 
12   (c) Copyright 2001 - 2011  zones
13   (c) Copyright 2002 - 2005  107
14   (c) Copyright 2002         PB1400c
15   (c) Copyright 2004         Alexander and Sander
16   (c) Copyright 2004 - 2005  Steven Seeger
17   (c) Copyright 2005         Ryan Vogt
18  ***********************************************************************************/
19 
20 
21 #include "snes9x.h"
22 #include "memmap.h"
23 #include "apu.h"
24 #include "display.h"
25 #include "blit.h"
26 
27 #include <OpenGL/OpenGL.h>
28 #include <OpenGL/CGLRenderers.h>
29 #include <OpenGL/gl.h>
30 #include <OpenGL/glu.h>
31 #include <OpenGL/glext.h>
32 #include <AGL/agl.h>
33 #include <sys/time.h>
34 
35 #include "mac-prefix.h"
36 #include "mac-cheatfinder.h"
37 #include "mac-coreimage.h"
38 #include "mac-os.h"
39 #include "mac-quicktime.h"
40 #include "mac-screenshot.h"
41 #include "mac-render.h"
42 
43 typedef void (* Blitter) (uint8 *, int, uint8 *, int, int, int);
44 
45 static OSStatus BlitMPGLTask (void *);
46 static OSStatus PrepareMPBlitGL (void);
47 static void S9xInitFullScreen (void);
48 static void S9xDeinitFullScreen (void);
49 static void S9xInitWindowMode (void);
50 static void S9xDeinitWindowMode (void);
51 static void S9xInitOpenGLFullScreen (void);
52 static void S9xDeinitOpenGLFullScreen (void);
53 static void S9xInitOpenGLWindowMode (void);
54 static void S9xDeinitOpenGLWindowMode (void);
55 static void S9xInitBlitGL (void);
56 static void S9xDeinitBlitGL (void);
57 static void S9xInitOpenGLContext (void);
58 static void S9xDeinitOpenGLContext (void);
59 static void S9xInitCoreImage (void);
60 static void S9xDeinitCoreImage (void);
61 static void S9xPutImageOpenGL (int, int);
62 static void S9xPutImageBlitGL (int, int);
63 static void S9xPutImageBlitGL2 (int, int);
64 static void GLMakeScreenMesh (GLfloat *, int, int);
65 static void GLMakeTextureMesh (GLfloat *, int, int, float, float);
66 static void GLPrepareTexture (bool8, int, int, int, int, int, int);
67 static inline void RenderBlitScreen (Blitter, int, int, int, int, int, uint16 *);
68 #ifndef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
69 static void SetBestDisplayMode (int, int);
70 #endif
71 
72 enum
73 {
74 	kMPBlitFrame = 1,
75 	kMPBlitDone,
76 	kMPBlitNone
77 };
78 
79 enum
80 {
81 	kGL256256 = 0,
82 	kGL256512,
83 	kGL512256,
84 	kGL512512,
85 	kGLBlit2x,
86 	kGLBlit3x,
87 	kGLBlit4x,
88 	kGLNTS256,
89 	kGLNTS512,
90 	kGLNumTextures
91 };
92 
93 enum
94 {
95 	kSC2xNormal = 0,
96 	kSC2xExtend,
97 	kSC2xNHiRes,
98 	kSC2xEHiRes,
99 	kSC2xNInter,
100 	kSC2xEInter,
101 	kSC3xNormal,
102 	kSC3xExtend,
103 	kSC3xNHiRes,
104 	kSC3xEHiRes,
105 	kSCNTNormal,
106 	kSCNTExtend,
107 	kSCNumTextures
108 };
109 
110 enum
111 {
112 	kSCMeshX = 10,
113 	kSCMeshY = 9
114 };
115 
116 typedef struct
117 {
118 	Blitter		blitFn;
119 	int			nx;
120 	int			srcWidth;
121 	int			srcHeight;
122 	int			copyWidth;
123 	int			copyHeight;
124 	uint16		*gfxBuffer;
125 }	MPData;
126 
127 typedef struct
128 {
129 	GLint		internal_format;
130 	GLint		format;
131 	GLint		type;
132 	GLenum		target;
133 	GLuint		textures[kGLNumTextures];
134 	GLfloat		vertex[kGLNumTextures][8];
135 	GLint		texW[kGLNumTextures];
136 	GLint		texH[kGLNumTextures];
137 	GLboolean   rangeExt;
138 	GLint		storage_hint;
139 	GLint		storage_apple;
140 	GLfloat		agp_texturing;
141 }	OpenGLData;
142 
143 static uint16				*gfxScreen[2],
144 							*snesScreenA,
145 							*snesScreenB;
146 static uint8				*blitGLBuffer;
147 
148 static CGDirectDisplayID	gGameDisplayID;
149 
150 static MPTaskID				taskID            = NULL;
151 static MPQueueID			notificationQueue = NULL,
152 							taskQueue         = NULL;
153 static MPSemaphoreID		readySemaphore    = NULL;
154 static MPData				*mpBlit           = NULL;
155 
156 static OpenGLData			OpenGL;
157 static CGLContextObj		glContext;
158 static AGLContext			agContext;
159 static CGLPixelFormatObj	cglpix;
160 static AGLPixelFormat		aglpix;
161 static GLint				glSwapInterval    = 0;
162 static GLint				agSwapInterval    = 0;
163 #ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
164 static CFDictionaryRef		oldDisplayMode;
165 #else
166 static CGDisplayModeRef		oldDisplayModeRef;
167 #endif
168 static CGImageRef			cgGameImage       = NULL,
169 							cgBlitImage       = NULL;
170 
171 static int					whichBuf          = 0;
172 static int					textureNum        = 0;
173 static int					prevBlitWidth, prevBlitHeight;
174 static int					imageWidth[2], imageHeight[2];
175 static int					nx                = 2;
176 
177 static GLfloat				*scTexArray[kSCNumTextures];
178 static GLfloat				*scScnArray;
179 
180 static struct timeval		bencht1, bencht2;
181 
182 static const int			ntsc_width = SNES_NTSC_OUT_WIDTH(SNES_WIDTH); // 602
183 
184 
InitGraphics(void)185 void InitGraphics (void)
186 {
187 	int	safemarginbytes = (520 * 520 - 512 * 512) * 2;
188 
189 	snesScreenA  = (uint16 *) calloc( 520 *  520 * 2, 1);
190 	snesScreenB  = (uint16 *) calloc( 520 *  520 * 2, 1);
191 	blitGLBuffer = (uint8  *) calloc(1024 * 1024 * 2, 1);
192 
193 	gfxScreen[0] = snesScreenA + (safemarginbytes >> 2);
194 	gfxScreen[1] = snesScreenB + (safemarginbytes >> 2);
195 
196 	GFX.Pitch    = 512 * 2;
197 	GFX.Screen   = gfxScreen[0];
198 
199 	if (!snesScreenA || !snesScreenB || !blitGLBuffer)
200 		QuitWithFatalError(0, "render 01");
201 
202 	if (!S9xBlitFilterInit()      |
203 		!S9xBlit2xSaIFilterInit() |
204 		!S9xBlitHQ2xFilterInit()  |
205 		!S9xBlitNTSCFilterInit())
206 		QuitWithFatalError(0, "render 02");
207 
208 	switch (videoMode)
209 	{
210 		default:
211 		case VIDEOMODE_NTSC_C:
212 		case VIDEOMODE_NTSC_TV_C:
213 			S9xBlitNTSCFilterSet(&snes_ntsc_composite);
214 			break;
215 
216 		case VIDEOMODE_NTSC_S:
217 		case VIDEOMODE_NTSC_TV_S:
218 			S9xBlitNTSCFilterSet(&snes_ntsc_svideo);
219 			break;
220 
221 		case VIDEOMODE_NTSC_R:
222 		case VIDEOMODE_NTSC_TV_R:
223 			S9xBlitNTSCFilterSet(&snes_ntsc_rgb);
224 			break;
225 
226 		case VIDEOMODE_NTSC_M:
227 		case VIDEOMODE_NTSC_TV_M:
228 			S9xBlitNTSCFilterSet(&snes_ntsc_monochrome);
229 			break;
230 	}
231 }
232 
DeinitGraphics(void)233 void DeinitGraphics (void)
234 {
235 	S9xBlitNTSCFilterDeinit();
236 	S9xBlitHQ2xFilterDeinit();
237 	S9xBlit2xSaIFilterDeinit();
238 	S9xBlitFilterDeinit();
239 
240 	if (snesScreenA)
241 	{
242 		free(snesScreenA);
243 		snesScreenA  = NULL;
244 	}
245 
246 	if (snesScreenB)
247 	{
248 		free(snesScreenB);
249 		snesScreenB  = NULL;
250 	}
251 
252 	if (blitGLBuffer)
253 	{
254 		free(blitGLBuffer);
255 		blitGLBuffer = NULL;
256 	}
257 }
258 
DrawPauseScreen(CGContextRef ctx,HIRect bounds)259 void DrawPauseScreen (CGContextRef ctx, HIRect bounds)
260 {
261 	CGImageRef	image;
262 	CGRect		rct;
263 	float		sh, mh, rofs, ry;
264 
265 	if ((IPPU.RenderedScreenWidth == 0) || (IPPU.RenderedScreenHeight == 0))
266 		return;
267 
268 	sh = (float) ((IPPU.RenderedScreenHeight > 256) ? IPPU.RenderedScreenHeight : IPPU.RenderedScreenHeight * 2);
269 	mh = (float) (SNES_HEIGHT_EXTENDED * 2);
270 
271 	if (drawoverscan)
272 	{
273 		rofs = (mh - sh) / mh;
274 		ry   = sh / mh;
275 	}
276 	else
277 	if (windowExtend)
278 	{
279 		rofs = (mh - sh) / mh / 2.0f;
280 		ry   = sh / mh;
281 	}
282 	else
283 	{
284 		rofs = 0.0f;
285 		ry   = 1.0f;
286 	}
287 
288 	image = CreateGameScreenCGImage();
289 	if (image)
290 	{
291 		CGContextSetRGBFillColor(ctx, 0.0f, 0.0f, 0.0f, 1.0f);
292 		CGContextFillRect(ctx, bounds);
293 
294 		rct = CGRectMake(0.0f, bounds.size.height * rofs, bounds.size.width, bounds.size.height * ry);
295 		CGContextDrawImage(ctx, rct, image);
296 
297 		CGContextSetRGBFillColor(ctx, 0.0f, 0.0f, 0.0f, 0.5f);
298 		CGContextFillRect(ctx, bounds);
299 
300 		CGImageRelease(image);
301 	}
302 }
303 
DrawFreezeDefrostScreen(uint8 * draw)304 void DrawFreezeDefrostScreen (uint8 *draw)
305 {
306 	const int	w = SNES_WIDTH << 1, h = kMacWindowHeight;
307 
308 	imageWidth[0] = imageHeight[0] = 0;
309 	imageWidth[1] = imageHeight[1] = 0;
310 	prevBlitWidth = prevBlitHeight = 0;
311 
312 	if ((drawingMethod == kDrawingBlitGL) && multiprocessor)
313 	{
314 		MPWaitOnSemaphore(readySemaphore, kDurationForever);
315 		printf("MP: Send dummy signal.\n");
316 		MPNotifyQueue(taskQueue, (void *) kMPBlitNone, 0, 0);
317 	}
318 
319 	if (nx < 0 && !ciFilterEnable)
320 	{
321 		for (int y = 0; y < h; y++)
322 			memcpy(blitGLBuffer + y * 1024 * 2, draw + y * w * 2, w * 2);
323 	}
324 	else
325 		memcpy(blitGLBuffer, draw, w * h * 2);
326 
327 	S9xPutImageBlitGL2(512, kMacWindowHeight);
328 }
329 
ClearGFXScreen(void)330 void ClearGFXScreen (void)
331 {
332 	memset(gfxScreen[0], 0,  512 *  512 * 2);
333 	memset(gfxScreen[1], 0,  512 *  512 * 2);
334 	memset(blitGLBuffer, 0, 1024 * 1024 * 2);
335 
336 	S9xBlitClearDelta();
337 
338 	imageWidth[0] = imageHeight[0] = 0;
339 	imageWidth[1] = imageHeight[1] = 0;
340 	prevBlitWidth = prevBlitHeight = 0;
341 
342 	if (fullscreen)
343 	{
344 		CGLSetCurrentContext(glContext);
345 		glViewport(0, 0, glScreenW, glScreenH);
346 	}
347 	else
348 	{
349 		aglSetCurrentContext(agContext);
350 		aglUpdateContext(agContext);
351 		glViewport(0, 0, (GLsizei) gWindowRect.size.width, (GLsizei) gWindowRect.size.height);
352 	}
353 
354 	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
355 
356 	for (int i = 0; i < 2; i++)
357 	{
358 		glClear(GL_COLOR_BUFFER_BIT);
359 
360 		if (fullscreen)
361 			CGLFlushDrawable(glContext);
362 		else
363 			aglSwapBuffers(agContext);
364 	}
365 }
366 
367 #ifndef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
SetBestDisplayMode(int width,int height)368 static void SetBestDisplayMode (int width, int height)
369 {
370 	if (autoRes || !gl32bit)
371 	{
372 		CGError				err;
373 		CGDisplayModeRef	mode;
374 		CFArrayRef			array;
375 		CFStringRef			pixenc, pix;
376 		CFIndex				n, i;
377 		size_t				w, h;
378 		bool				r;
379 
380 		pixenc = gl32bit ? CFSTR(IO32BitDirectPixels) : CFSTR(IO16BitDirectPixels);
381 
382 		array = CGDisplayCopyAllDisplayModes(gGameDisplayID, NULL);
383 		n = CFArrayGetCount(array);
384 
385 		for (i = 0; i < n; i++)
386 		{
387 			mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(array, i);
388 
389 			w   = CGDisplayModeGetWidth(mode);
390 			h   = CGDisplayModeGetHeight(mode);
391 			pix = CGDisplayModeCopyPixelEncoding(mode);
392 			r   = CFStringCompare(pix, pixenc, 0) == kCFCompareEqualTo;
393 			CFRelease(pix);
394 
395 			if (w == (size_t) width && h == (size_t) height && r)
396 				break;
397 		}
398 
399 		if (i < n)
400 			err = CGDisplaySetDisplayMode(gGameDisplayID, mode, NULL);
401 
402 		CFRelease(array);
403 	}
404 }
405 #endif
406 
S9xInitFullScreen(void)407 static void S9xInitFullScreen (void)
408 {
409 	DeinitGameWindow();
410 
411 	size_t	width, height;
412 
413 	width  = autoRes ? 640 : CGDisplayPixelsWide(gGameDisplayID);
414 	height = autoRes ? 480 : CGDisplayPixelsHigh(gGameDisplayID);
415 
416 #ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
417 	CFDictionaryRef	mode;
418 	boolean_t		exactMatch;
419 	size_t			depth = gl32bit ? 32 : 16;
420 
421 	oldDisplayMode = CGDisplayCurrentMode(gGameDisplayID);
422 	mode = CGDisplayBestModeForParameters(gGameDisplayID, depth, width, height, &exactMatch);
423 	CGDisplayCapture(gGameDisplayID);
424 	CGDisplaySwitchToMode(gGameDisplayID, mode);
425 #else
426 	oldDisplayModeRef = CGDisplayCopyDisplayMode(gGameDisplayID);
427 	CGDisplayCapture(gGameDisplayID);
428 	SetBestDisplayMode(width, height);
429 #endif
430 
431 	CGDisplayErr		cgErr;
432 	CGDisplayCount		numDisplays, maxDisplays = 32;
433 	CGDirectDisplayID	activeDisplays[32];
434 
435 	cgErr = CGGetActiveDisplayList(maxDisplays, activeDisplays, &numDisplays);
436 	if (cgErr == noErr)
437 	{
438 		if ((macControllerOption == SNES_MOUSE) || (macControllerOption == SNES_MOUSE_SWAPPED) || (numDisplays == 1))
439 			CGDisplayHideCursor(gGameDisplayID);
440 
441 		if ((macControllerOption == SNES_MOUSE) || (macControllerOption == SNES_MOUSE_SWAPPED))
442 		{
443 			CGDisplayMoveCursorToPoint(gGameDisplayID, CGPointMake((float) (width >> 1), (float) (height >> 1)));
444 			CGAssociateMouseAndMouseCursorPosition(false);
445 		}
446 	}
447 }
448 
S9xDeinitFullScreen(void)449 static void S9xDeinitFullScreen (void)
450 {
451 	CGAssociateMouseAndMouseCursorPosition(true);
452 	CGDisplayShowCursor(gGameDisplayID);
453 
454 #ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
455 	CGDisplaySwitchToMode(gGameDisplayID, oldDisplayMode);
456 #else
457 	CGError	err;
458 
459 	err = CGDisplaySetDisplayMode(gGameDisplayID, oldDisplayModeRef, NULL);
460 	CGDisplayModeRelease(oldDisplayModeRef);
461 #endif
462 
463 	CGDisplayRelease(gGameDisplayID);
464 }
465 
S9xInitWindowMode(void)466 static void S9xInitWindowMode (void)
467 {
468 	Rect	rct;
469 	size_t	width, height;
470 
471 	width  = CGDisplayPixelsWide(gGameDisplayID);
472 	height = CGDisplayPixelsHigh(gGameDisplayID);
473 
474 #ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
475 	CFDictionaryRef	mode;
476 	boolean_t		exactMatch;
477 	size_t			depth = gl32bit ? 32 : 16;
478 
479 	oldDisplayMode = CGDisplayCurrentMode(gGameDisplayID);
480 	mode = CGDisplayBestModeForParameters(gGameDisplayID, depth, width, height, &exactMatch);
481 	if (exactMatch)
482 		CGDisplaySwitchToMode(gGameDisplayID, mode);
483 #else
484 	oldDisplayModeRef = CGDisplayCopyDisplayMode(gGameDisplayID);
485 	SetBestDisplayMode(width, height);
486 #endif
487 
488 	InitGameWindow();
489 	ShowWindow(gWindow);
490 
491 	GetWindowBounds(gWindow, kWindowContentRgn, &rct);
492 	gWindowRect = CGRectMake((float) rct.left, (float) rct.top, (float) (rct.right - rct.left), (float) (rct.bottom - rct.top));
493 
494 	UpdateGameWindow();
495 }
496 
S9xDeinitWindowMode(void)497 static void S9xDeinitWindowMode (void)
498 {
499 #ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
500 	CGDisplaySwitchToMode(gGameDisplayID, oldDisplayMode);
501 #else
502 	CGError	err;
503 
504 	err = CGDisplaySetDisplayMode(gGameDisplayID, oldDisplayModeRef, NULL);
505 	CGDisplayModeRelease(oldDisplayModeRef);
506 #endif
507 
508 	UpdateGameWindow();
509 }
510 
S9xInitOpenGLFullScreen(void)511 static void S9xInitOpenGLFullScreen (void)
512 {
513 	CGOpenGLDisplayMask	displayMask;
514 	GLint 				numPixelFormats;
515 
516 	displayMask = CGDisplayIDToOpenGLDisplayMask(gGameDisplayID);
517 	CGLPixelFormatAttribute	attribs[] = { (CGLPixelFormatAttribute) kCGLPFAFullScreen,
518 										  (CGLPixelFormatAttribute) kCGLPFADoubleBuffer,
519 										  (CGLPixelFormatAttribute) kCGLPFAAccelerated,
520 										  (CGLPixelFormatAttribute) kCGLPFANoRecovery,
521 										  (CGLPixelFormatAttribute) kCGLPFAColorSize,
522 										  (CGLPixelFormatAttribute) (gl32bit ? 32 : 16),
523 										  (CGLPixelFormatAttribute) kCGLPFADisplayMask,
524 										  (CGLPixelFormatAttribute) displayMask,
525 										  (CGLPixelFormatAttribute) 0 };
526 
527 	CGLChoosePixelFormat(attribs, &cglpix, &numPixelFormats);
528 	CGLCreateContext(cglpix, NULL, &glContext);
529 	glSwapInterval = vsync ? 1 : 0;
530 	if (extraOptions.benchmark)
531 		glSwapInterval = 0;
532 	CGLSetParameter(glContext, kCGLCPSwapInterval, &glSwapInterval);
533 	CGLSetCurrentContext(glContext);
534 
535 #ifdef MAC_LEOPARD_TIGER_PANTHER_SUPPORT
536 	CGLSetFullScreen(glContext);
537 #else
538 	CGLSetFullScreenOnDisplay(glContext, CGDisplayIDToOpenGLDisplayMask(gGameDisplayID));
539 #endif
540 
541 	glScreenW = CGDisplayPixelsWide(gGameDisplayID);
542 	glScreenH = CGDisplayPixelsHigh(gGameDisplayID);
543 }
544 
S9xDeinitOpenGLFullScreen(void)545 static void S9xDeinitOpenGLFullScreen (void)
546 {
547 	if (glContext)
548 	{
549 		CGLSetCurrentContext(NULL);
550 		CGLClearDrawable(glContext);
551 		CGLDestroyContext(glContext);
552 		CGLDestroyPixelFormat(cglpix);
553 	}
554 }
555 
S9xInitOpenGLWindowMode(void)556 static void S9xInitOpenGLWindowMode (void)
557 {
558 	GLint	attribs[] = { AGL_RGBA,
559 						  AGL_DOUBLEBUFFER,
560 						  AGL_ACCELERATED,
561 						  AGL_NO_RECOVERY,
562 						  AGL_PIXEL_SIZE, gl32bit ? 32 : 16,
563 						  AGL_NONE };
564 
565 	aglpix = aglChoosePixelFormat(NULL, 0, attribs);
566 	agContext = aglCreateContext(aglpix, NULL);
567 
568 	if (systemVersion >= 0x1050)
569 		aglSetWindowRef(agContext, gWindow);
570 #ifdef MAC_TIGER_PANTHER_SUPPORT
571 	else
572 		aglSetDrawable(agContext, GetWindowPort(gWindow));
573 #endif
574 
575 	agSwapInterval = vsync ? 1 : 0;
576 	if (extraOptions.benchmark)
577 		agSwapInterval = 0;
578 	aglSetInteger(agContext, AGL_SWAP_INTERVAL, &agSwapInterval);
579 	aglSetCurrentContext(agContext);
580 
581 	if (systemVersion >= 0x1040)
582 	{
583 		aglGetCGLPixelFormat(aglpix, (void **) &cglpix);
584 		aglGetCGLContext(agContext, (void **) &glContext);
585 	}
586 }
587 
S9xDeinitOpenGLWindowMode(void)588 static void S9xDeinitOpenGLWindowMode (void)
589 {
590 	if (agContext)
591 	{
592 		if (systemVersion >= 0x1050)
593 			aglSetWindowRef(agContext, NULL);
594 	#ifdef MAC_TIGER_PANTHER_SUPPORT
595 		else
596 			aglSetDrawable(agContext, NULL);
597 	#endif
598 
599 		aglSetCurrentContext(NULL);
600 		aglDestroyContext(agContext);
601 		aglDestroyPixelFormat(aglpix);
602 	}
603 }
604 
S9xInitBlitGL(void)605 static void S9xInitBlitGL (void)
606 {
607 	if (multiprocessor)
608 	{
609 		printf("MP: Creating BlitGL thread.\n");
610 
611 		if (noErr != PrepareMPBlitGL())
612 			multiprocessor = false;
613 	}
614 }
615 
S9xDeinitBlitGL(void)616 static void S9xDeinitBlitGL (void)
617 {
618 	if (multiprocessor)
619 	{
620 		MPNotifyQueue(taskQueue, (void *) kMPBlitDone, 0, 0);
621 		MPWaitOnQueue(notificationQueue, NULL, NULL, NULL, kDurationForever);
622 		MPDeleteQueue(notificationQueue);
623 		notificationQueue = NULL;
624 
625 		printf("MP: Successfully received terminate signal from BlitGL thread.\n");
626 	}
627 }
628 
GLPrepareTexture(bool8 useRange,int texNo,int rangeOnW,int rangeOnH,int rangeOffW,int rangeOffH,int filter)629 static void GLPrepareTexture (bool8 useRange, int texNo, int rangeOnW, int rangeOnH, int rangeOffW, int rangeOffH, int filter)
630 {
631 	bool8	rangeAvailable = OpenGL.rangeExt & useRange;
632 
633 	OpenGL.texW[texNo] = rangeAvailable ? rangeOnW : rangeOffW;
634 	OpenGL.texH[texNo] = rangeAvailable ? rangeOnH : rangeOffH;
635 
636 	OpenGL.vertex[texNo][0] = 0;
637 	OpenGL.vertex[texNo][1] = 0;
638 	OpenGL.vertex[texNo][2] = rangeAvailable ? rangeOnW : 1;
639 	OpenGL.vertex[texNo][3] = 0;
640 	OpenGL.vertex[texNo][4] = rangeAvailable ? rangeOnW : 1;
641 	OpenGL.vertex[texNo][5] = rangeAvailable ? rangeOnH : 1;
642 	OpenGL.vertex[texNo][6] = 0;
643 	OpenGL.vertex[texNo][7] = rangeAvailable ? rangeOnH : 1;
644 
645 	glBindTexture(OpenGL.target, OpenGL.textures[texNo]);
646 
647 	if (rangeAvailable)
648 	{
649 		glTextureRangeAPPLE(OpenGL.target, OpenGL.texW[texNo] * OpenGL.texH[texNo] * 2, GFX.Screen);
650 		glTexParameteri(OpenGL.target, GL_TEXTURE_STORAGE_HINT_APPLE, OpenGL.storage_hint);
651 	}
652 
653 	glTexParameterf(OpenGL.target, GL_TEXTURE_PRIORITY, OpenGL.agp_texturing);
654 	glTexParameteri(OpenGL.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
655 	glTexParameteri(OpenGL.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
656 	glTexParameteri(OpenGL.target, GL_TEXTURE_MAG_FILTER, filter);
657 	glTexParameteri(OpenGL.target, GL_TEXTURE_MIN_FILTER, filter);
658 	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
659 	glTexImage2D(OpenGL.target, 0, OpenGL.internal_format, OpenGL.texW[texNo], OpenGL.texH[texNo], 0, OpenGL.format, OpenGL.type, GFX.Screen);
660 }
661 
GLMakeScreenMesh(GLfloat * vertex3D,int meshx,int meshy)662 static void GLMakeScreenMesh (GLfloat *vertex3D, int meshx, int meshy)
663 {
664 	GLfloat *v;
665 	float   warp;
666 
667 	v = vertex3D;
668 	warp = macCurvatureWarp * 0.001f;
669 
670 	for (int y = 0; y < meshy; y++)
671 	{
672 		for (int x = 0; x <= meshx; x++)
673 		{
674 			float	u1, v1, v2;
675 
676 			u1 = -1.0f + 2.0f / (float) meshx * (float)  x;
677 			v1 = -1.0f + 2.0f / (float) meshy * (float)  y;
678 			v2 = -1.0f + 2.0f / (float) meshy * (float) (y + 1);
679 
680 			*v++ = u1;
681 			*v++ = v2;
682 			*v++ = -1.0f - (u1 * u1 + v2 * v2) * warp;
683 
684 			*v++ = u1;
685 			*v++ = v1;
686 			*v++ = -1.0f - (u1 * u1 + v1 * v1) * warp;
687 		}
688 	}
689 }
690 
GLMakeTextureMesh(GLfloat * vertex2D,int meshx,int meshy,float lx,float ly)691 static void GLMakeTextureMesh (GLfloat *vertex2D, int meshx, int meshy, float lx, float ly)
692 {
693 	GLfloat *v;
694 
695 	v = vertex2D;
696 
697 	for (int y = meshy; y > 0; y--)
698 	{
699 		for (int x = 0; x <= meshx; x++)
700 		{
701 			float	u1, v1, v2;
702 
703 			u1 = lx / (float) meshx * (float)  x;
704 			v1 = ly / (float) meshy * (float)  y;
705 			v2 = ly / (float) meshy * (float) (y - 1);
706 
707 			*v++ = u1;
708 			*v++ = v2;
709 
710 			*v++ = u1;
711 			*v++ = v1;
712 		}
713 	}
714 }
715 
S9xInitOpenGLContext(void)716 static void S9xInitOpenGLContext (void)
717 {
718 	OpenGL.internal_format = GL_RGB5_A1;
719 	OpenGL.format          = GL_BGRA;
720 	OpenGL.type            = GL_UNSIGNED_SHORT_1_5_5_5_REV;
721 	OpenGL.rangeExt        = gluCheckExtension((const GLubyte *) "GL_APPLE_texture_range", glGetString(GL_EXTENSIONS));
722 	OpenGL.target          = OpenGL.rangeExt ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D;
723 
724 	OpenGL.storage_apple   = extraOptions.glUseClientStrageApple ? 1    : 0;
725 	OpenGL.agp_texturing   = extraOptions.glUseTexturePriority   ? 0.0f : 1.0f;
726 	switch (extraOptions.glStorageHint)
727 	{
728 		case 1:	OpenGL.storage_hint = GL_STORAGE_PRIVATE_APPLE;	break;
729 		case 2:	OpenGL.storage_hint = GL_STORAGE_CACHED_APPLE;	break;
730 		case 3:	OpenGL.storage_hint = GL_STORAGE_SHARED_APPLE;	break;
731 	}
732 
733 	if (screencurvature || videoMode >= VIDEOMODE_NTSC_C || extraOptions.glForceNoTextureRectangle)
734 	{
735 		OpenGL.rangeExt = false;
736 		OpenGL.target   = GL_TEXTURE_2D;
737 	}
738 
739 	printf("TextureRange: %s\n", OpenGL.rangeExt ? "enable" : "disable");
740 
741 	glDisable(GL_BLEND);
742 	glDisable(GL_DITHER);
743 	glDisable(GL_LIGHTING);
744 	glDisable(GL_DEPTH_TEST);
745 
746 	glEnable(GL_CULL_FACE);
747 	glPolygonMode(GL_FRONT, GL_FILL);
748 	glCullFace(GL_BACK);
749 
750 	glDisable(GL_TEXTURE_2D);
751 	glDisable(GL_TEXTURE_RECTANGLE_EXT);
752 	glEnable(OpenGL.target);
753 
754 	glGenTextures(kGLNumTextures, OpenGL.textures);
755 
756 	glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, OpenGL.storage_apple);
757 	glPixelStorei(GL_UNPACK_ALIGNMENT, 8);
758 
759 	int	filter = (videoMode == VIDEOMODE_SMOOTH) ? GL_LINEAR : GL_NEAREST;
760 	GLPrepareTexture(true,  kGL256256, SNES_WIDTH,     SNES_HEIGHT_EXTENDED,      256,  256, filter);
761 	GLPrepareTexture(true,  kGL256512, SNES_WIDTH,     SNES_HEIGHT_EXTENDED * 2,  256,  512, filter);
762 	GLPrepareTexture(true,  kGL512256, SNES_WIDTH * 2, SNES_HEIGHT_EXTENDED,      512,  256, filter);
763 	GLPrepareTexture(true,  kGL512512, SNES_WIDTH * 2, SNES_HEIGHT_EXTENDED * 2,  512,  512, filter);
764 	GLPrepareTexture(true,  kGLBlit2x, SNES_WIDTH * 2, SNES_HEIGHT_EXTENDED * 2,  512,  512, GL_LINEAR);
765 	GLPrepareTexture(true,  kGLBlit3x, SNES_WIDTH * 3, SNES_HEIGHT_EXTENDED * 3, 1024, 1024, GL_LINEAR);
766 	GLPrepareTexture(true,  kGLBlit4x, SNES_WIDTH * 4, SNES_HEIGHT_EXTENDED * 4, 1024, 1024, GL_LINEAR);
767 	GLPrepareTexture(false, kGLNTS256, 1024,           256,                      1024,  256, GL_LINEAR);
768 	GLPrepareTexture(false, kGLNTS512, 1024,           512,                      1024,  512, GL_LINEAR);
769 
770 	if (!screencurvature)
771 	{
772 		glMatrixMode(GL_PROJECTION);
773 		glLoadIdentity();
774 
775 		glMatrixMode(GL_MODELVIEW);
776 		glLoadIdentity();
777 
778 		glDisableClientState(GL_VERTEX_ARRAY);
779 		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
780 	}
781 	else
782 	{
783 		glMatrixMode(GL_PROJECTION);
784 		glLoadIdentity();
785 		glFrustum(-1.0, 1.0, -1.0, 1.0, 0.95, 5.0);
786 
787 		glMatrixMode(GL_MODELVIEW);
788 		glLoadIdentity();
789 
790 		glEnableClientState(GL_VERTEX_ARRAY);
791 		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
792 
793 		int	mesh = (kSCMeshX + 1) * 2 * kSCMeshY * 2;
794 		scTexArray[kSC2xNormal] = new GLfloat [mesh];
795 		scTexArray[kSC2xExtend] = new GLfloat [mesh];
796 		scTexArray[kSC2xNHiRes] = new GLfloat [mesh];
797 		scTexArray[kSC2xEHiRes] = new GLfloat [mesh];
798 		scTexArray[kSC2xNInter] = new GLfloat [mesh];
799 		scTexArray[kSC2xEInter] = new GLfloat [mesh];
800 		scTexArray[kSC3xNormal] = new GLfloat [mesh];
801 		scTexArray[kSC3xExtend] = new GLfloat [mesh];
802 		scTexArray[kSC3xNHiRes] = new GLfloat [mesh];
803 		scTexArray[kSC3xEHiRes] = new GLfloat [mesh];
804 		scTexArray[kSCNTNormal] = new GLfloat [mesh];
805 		scTexArray[kSCNTExtend] = new GLfloat [mesh];
806 
807 		GLMakeTextureMesh(scTexArray[kSC2xNormal], kSCMeshX, kSCMeshY,                         1.0f, 224.0f /  256.0f);
808 		GLMakeTextureMesh(scTexArray[kSC2xExtend], kSCMeshX, kSCMeshY,                         1.0f, 239.0f /  256.0f);
809 		GLMakeTextureMesh(scTexArray[kSC2xNHiRes], kSCMeshX, kSCMeshY,                         1.0f, 224.0f /  512.0f);
810 		GLMakeTextureMesh(scTexArray[kSC2xEHiRes], kSCMeshX, kSCMeshY,                         1.0f, 239.0f /  512.0f);
811 		GLMakeTextureMesh(scTexArray[kSC2xNInter], kSCMeshX, kSCMeshY,             256.0f /  512.0f, 224.0f /  256.0f);
812 		GLMakeTextureMesh(scTexArray[kSC2xEInter], kSCMeshX, kSCMeshY,             256.0f /  512.0f, 239.0f /  256.0f);
813 		GLMakeTextureMesh(scTexArray[kSC3xNormal], kSCMeshX, kSCMeshY,             768.0f / 1024.0f, 672.0f / 1024.0f);
814 		GLMakeTextureMesh(scTexArray[kSC3xExtend], kSCMeshX, kSCMeshY,             768.0f / 1024.0f, 717.0f / 1024.0f);
815 		GLMakeTextureMesh(scTexArray[kSC3xNHiRes], kSCMeshX, kSCMeshY,             768.0f / 1024.0f, 672.0f / 2048.0f);
816 		GLMakeTextureMesh(scTexArray[kSC3xEHiRes], kSCMeshX, kSCMeshY,             768.0f / 1024.0f, 717.0f / 2048.0f);
817 		GLMakeTextureMesh(scTexArray[kSCNTNormal], kSCMeshX, kSCMeshY, (float) ntsc_width / 1024.0f, 224.0f /  256.0f);
818 		GLMakeTextureMesh(scTexArray[kSCNTExtend], kSCMeshX, kSCMeshY, (float) ntsc_width / 1024.0f, 239.0f /  256.0f);
819 
820 		scScnArray = new GLfloat [(kSCMeshX + 1) * 2 * kSCMeshY * 3];
821 		GLMakeScreenMesh(scScnArray, kSCMeshX, kSCMeshY);
822 	}
823 
824 	if (fullscreen)
825 	{
826 		CGLSetCurrentContext(glContext);
827 		glViewport(0, 0, glScreenW, glScreenH);
828 	}
829 	else
830 	{
831 		aglSetCurrentContext(agContext);
832 		aglUpdateContext(agContext);
833 		glViewport(0, 0, (GLsizei) gWindowRect.size.width, (GLsizei) gWindowRect.size.height);
834 	}
835 
836 	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
837 
838 	for (int i = 0; i < 2; i++)
839 	{
840 		glClear(GL_COLOR_BUFFER_BIT);
841 
842 		if (fullscreen)
843 			CGLFlushDrawable(glContext);
844 		else
845 			aglSwapBuffers(agContext);
846 	}
847 }
848 
S9xDeinitOpenGLContext(void)849 static void S9xDeinitOpenGLContext (void)
850 {
851 	if (screencurvature)
852 	{
853 		delete [] scTexArray[kSC2xNormal];
854 		delete [] scTexArray[kSC2xExtend];
855 		delete [] scTexArray[kSC2xNHiRes];
856 		delete [] scTexArray[kSC2xEHiRes];
857 		delete [] scTexArray[kSC2xNInter];
858 		delete [] scTexArray[kSC2xEInter];
859 		delete [] scTexArray[kSC3xNormal];
860 		delete [] scTexArray[kSC3xExtend];
861 		delete [] scTexArray[kSC3xNHiRes];
862 		delete [] scTexArray[kSC3xEHiRes];
863 		delete [] scTexArray[kSCNTNormal];
864 		delete [] scTexArray[kSCNTExtend];
865 		delete [] scScnArray;
866 
867 		scTexArray[kSC2xNormal] = NULL;
868 		scTexArray[kSC2xExtend] = NULL;
869 		scTexArray[kSC2xNHiRes] = NULL;
870 		scTexArray[kSC2xEHiRes] = NULL;
871 		scTexArray[kSC2xNInter] = NULL;
872 		scTexArray[kSC2xEInter] = NULL;
873 		scTexArray[kSC3xNormal] = NULL;
874 		scTexArray[kSC3xExtend] = NULL;
875 		scTexArray[kSC3xNHiRes] = NULL;
876 		scTexArray[kSC3xEHiRes] = NULL;
877 		scTexArray[kSCNTNormal] = NULL;
878 		scTexArray[kSCNTExtend] = NULL;
879 		scScnArray              = NULL;
880 	}
881 
882 	glDeleteTextures(kGLNumTextures, OpenGL.textures);
883 }
884 
S9xInitCoreImage(void)885 static void S9xInitCoreImage (void)
886 {
887 	cgGameImage = NULL;
888 	cgBlitImage = NULL;
889 
890 	InitCoreImageContext(glContext, cglpix);
891 }
892 
S9xDeinitCoreImage(void)893 static void S9xDeinitCoreImage (void)
894 {
895 	DeinitCoreImageContext();
896 
897 	if (cgGameImage)
898 	{
899 		CGImageRelease(cgGameImage);
900 		cgGameImage = NULL;
901 	}
902 
903 	if (cgBlitImage)
904 	{
905 		CGImageRelease(cgBlitImage);
906 		cgBlitImage = NULL;
907 	}
908 }
909 
GetGameDisplay(int * w,int * h)910 void GetGameDisplay (int *w, int *h)
911 {
912 	CGDisplayErr		cgErr;
913 	CGDisplayCount		numDisplays, maxDisplays = 32;
914 	CGDirectDisplayID	activeDisplays[32];
915 	CGPoint				windowAt;
916 
917 	gGameDisplayID = CGMainDisplayID();
918 
919 	windowAt = CGPointMake((float) windowPos[kWindowScreen].h, (float) windowPos[kWindowScreen].v);
920 
921 	cgErr = CGGetDisplaysWithPoint(windowAt, maxDisplays, activeDisplays, &numDisplays);
922 	if ((cgErr == noErr) && (numDisplays > 0))
923 	{
924 		for (unsigned int i = 0; i < numDisplays; i++)
925 		{
926 			if (activeDisplays[i] != CGMainDisplayID())
927 				gGameDisplayID = activeDisplays[i];
928 		}
929 	}
930 
931 	if (w != NULL && h != NULL)
932 	{
933 		*w = CGDisplayPixelsWide(gGameDisplayID);
934 		*h = CGDisplayPixelsHigh(gGameDisplayID);
935 	}
936 }
937 
S9xInitDisplay(int argc,char ** argv)938 void S9xInitDisplay (int argc, char **argv)
939 {
940 	if (directDisplay)
941 		return;
942 
943 	GetGameDisplay(NULL, NULL);
944 
945 	glScreenBounds = CGDisplayBounds(gGameDisplayID);
946 
947 	unlimitedCursor = CGPointMake(0.0f, 0.0f);
948 
949 	imageWidth[0] = imageHeight[0] = 0;
950 	imageWidth[1] = imageHeight[1] = 0;
951 	prevBlitWidth = prevBlitHeight = 0;
952 	GFX.Screen    = gfxScreen[0];
953 	whichBuf      = 0;
954 	textureNum    = 0;
955 
956 	switch (videoMode)
957 	{
958 		case VIDEOMODE_HQ4X:
959 			nx =  4;
960 			break;
961 
962 		case VIDEOMODE_HQ3X:
963 			nx =  3;
964 			break;
965 
966 		case VIDEOMODE_NTSC_C:
967 		case VIDEOMODE_NTSC_S:
968 		case VIDEOMODE_NTSC_R:
969 		case VIDEOMODE_NTSC_M:
970 			nx = -1;
971 			break;
972 
973 		case VIDEOMODE_NTSC_TV_C:
974 		case VIDEOMODE_NTSC_TV_S:
975 		case VIDEOMODE_NTSC_TV_R:
976 		case VIDEOMODE_NTSC_TV_M:
977 			nx = -2;
978 			break;
979 
980 		default:
981 			nx =  2;
982 			break;
983 	}
984 
985 	if (fullscreen)
986 	{
987 		S9xInitFullScreen();
988 		S9xInitOpenGLFullScreen();
989 	}
990 	else
991 	{
992 		S9xInitWindowMode();
993 		S9xInitOpenGLWindowMode();
994 	}
995 
996 	S9xInitOpenGLContext();
997 	if (ciFilterEnable)
998 		S9xInitCoreImage();
999 	if (drawingMethod == kDrawingBlitGL)
1000 		S9xInitBlitGL();
1001 
1002 	S9xSetSoundMute(false);
1003 	Microseconds((UnsignedWide *) &lastFrame);
1004 
1005 	windowResizeCount = 1;
1006 
1007 	gettimeofday(&bencht1, NULL);
1008 
1009 	directDisplay = true;
1010 }
1011 
S9xDeinitDisplay(void)1012 void S9xDeinitDisplay (void)
1013 {
1014 	if (!directDisplay)
1015 		return;
1016 
1017 	S9xSetSoundMute(true);
1018 
1019 	if (drawingMethod == kDrawingBlitGL)
1020 		S9xDeinitBlitGL();
1021 	if (ciFilterEnable)
1022 		S9xDeinitCoreImage();
1023 	S9xDeinitOpenGLContext();
1024 
1025 	if (fullscreen)
1026 	{
1027 		S9xDeinitOpenGLFullScreen();
1028 		S9xDeinitFullScreen();
1029 	}
1030 	else
1031 	{
1032 		S9xDeinitOpenGLWindowMode();
1033 		S9xDeinitWindowMode();
1034 	}
1035 
1036 	directDisplay = false;
1037 }
1038 
S9xInitUpdate(void)1039 bool8 S9xInitUpdate (void)
1040 {
1041 	return (true);
1042 }
1043 
S9xDeinitUpdate(int width,int height)1044 bool8 S9xDeinitUpdate (int width, int height)
1045 {
1046 	if (directDisplay)
1047 		S9xPutImage(width, height);
1048 
1049 	return (true);
1050 }
1051 
S9xContinueUpdate(int width,int height)1052 bool8 S9xContinueUpdate (int width, int height)
1053 {
1054 	return (true);
1055 }
1056 
RenderBlitScreen(Blitter Fn,int x,int sW,int sH,int cW,int cH,uint16 * buf)1057 static inline void RenderBlitScreen (Blitter Fn, int x, int sW, int sH, int cW, int cH, uint16 *buf)
1058 {
1059 	switch (x)
1060 	{
1061 		case -1:
1062 			(Fn) ((uint8 *) buf, sW * 2, blitGLBuffer, 1024 * 2, sW, sH);
1063 			break;
1064 
1065 		case -2:
1066 			if (sH > SNES_HEIGHT_EXTENDED)
1067 				(Fn) ((uint8 *) buf, sW * 2, blitGLBuffer, 1024 * 2, sW, sH);
1068 			else
1069 			{
1070 				uint8	*tmpBuffer = blitGLBuffer + (1024 * 512 * 2);
1071 				int		aligned    = ((ntsc_width + 2) >> 1) << 1;
1072 				(Fn) ((uint8 *) buf, sW * 2, tmpBuffer, 1024 * 2, sW, sH);
1073 				S9xBlitPixMixedTV1x2(tmpBuffer, 1024 * 2, blitGLBuffer, 1024 * 2, aligned, cH);
1074 				cH *= 2;
1075 			}
1076 
1077 			break;
1078 
1079 		default:
1080 			int	dstbytes = (OpenGL.rangeExt ? cW : ((cW > 512) ? 1024 : ((cW > 256) ? 512 : 256))) * 2;
1081 			(Fn) ((uint8 *) buf, sW * 2, blitGLBuffer, dstbytes, sW, sH);
1082 			break;
1083 	}
1084 
1085 	S9xPutImageBlitGL2(cW, cH);
1086 }
1087 
PrepareMPBlitGL(void)1088 static OSStatus PrepareMPBlitGL (void)
1089 {
1090 	OSStatus	err;
1091 
1092 	mpBlit = (MPData *) MPAllocateAligned(sizeof(MPData), kMPAllocateDefaultAligned, kMPAllocateClearMask);
1093 	if (!mpBlit)
1094 		return (memFullErr);
1095 
1096 	err = MPCreateQueue(&notificationQueue);
1097 	if (err == noErr)
1098 	{
1099 		err = MPCreateQueue(&taskQueue);
1100 		if (err == noErr)
1101 		{
1102 			err = MPCreateBinarySemaphore(&readySemaphore);
1103 			if (err == noErr)
1104 			{
1105 				MPSignalSemaphore(readySemaphore);
1106 				err = MPCreateTask(BlitMPGLTask, NULL, 0, notificationQueue, NULL, NULL, 0, &taskID);
1107 			}
1108 		}
1109 	}
1110 
1111 	return (err);
1112 }
1113 
BlitMPGLTask(void * parameter)1114 static OSStatus BlitMPGLTask (void *parameter)
1115 {
1116 	OSStatus	err = noErr;
1117 	int32		theCommand, param1, param2;
1118 
1119 	printf("MP: Entered BlitGL thread.\n");
1120 
1121 	for (;;)
1122 	{
1123 		err = MPWaitOnQueue(taskQueue, (void **) &theCommand, (void **) &param1, (void **) &param2, kDurationForever);
1124 		if (err)
1125 			break;
1126 
1127 		if (theCommand == kMPBlitFrame)
1128 		{
1129 			RenderBlitScreen(mpBlit->blitFn, mpBlit->nx, mpBlit->srcWidth, mpBlit->srcHeight, mpBlit->copyWidth, mpBlit->copyHeight, mpBlit->gfxBuffer);
1130 			MPSignalSemaphore(readySemaphore);
1131 		}
1132 		else
1133 		if (theCommand == kMPBlitNone)
1134 			MPSignalSemaphore(readySemaphore);
1135 		else
1136 		if (theCommand == kMPBlitDone)
1137 			break;
1138 		else
1139 		{
1140 			err = userCanceledErr;
1141 			break;
1142 		}
1143 	}
1144 
1145 	MPFree(mpBlit);
1146 	MPDeleteSemaphore(readySemaphore);
1147 	MPDeleteQueue(taskQueue);
1148 	mpBlit         = NULL;
1149 	readySemaphore = NULL;
1150 	taskQueue      = NULL;
1151 
1152 	printf("MP: Exited BlitGL thread.\n");
1153 
1154 	return (err);
1155 }
1156 
S9xPutImage(int width,int height)1157 void S9xPutImage (int width, int height)
1158 {
1159 	static float	fps   = 0.0f;
1160 	static long		count = 0;
1161 	static char		text[32];
1162 
1163 	if (extraOptions.benchmark)
1164 	{
1165 		uint16	*basePtr;
1166 		long	delta;
1167 		size_t	len;
1168 
1169 		count++;
1170 
1171 		gettimeofday(&bencht2, NULL);
1172 
1173 		delta = 1000000 * (bencht2.tv_sec - bencht1.tv_sec) + (bencht2.tv_usec - bencht1.tv_usec);
1174 		if (delta > 1000000)
1175 		{
1176 			fps = (1000000.0f * (float) count) / (float) delta;
1177 			count = 0;
1178 
1179 			gettimeofday(&bencht1, NULL);
1180 		}
1181 
1182 		sprintf(text, "%.1f", fps);
1183 
1184 		basePtr = GFX.Screen + 1;
1185 		len = strlen(text);
1186 
1187 		for (unsigned int i = 0; i < len; i++)
1188 		{
1189 			S9xDisplayChar(basePtr, text[i]);
1190 			basePtr += (8 - 1);
1191 		}
1192 	}
1193 	else
1194 	{
1195 		if (cfIsWatching)
1196 			CheatFinderDrawWatchAddr();
1197 
1198 		if (Settings.DisplayFrameRate)
1199 		{
1200 			static int	drawnFrames[60] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1201 											1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
1202 			static int	tableIndex = 0;
1203 			int			frameCalc  = 0;
1204 
1205 			drawnFrames[tableIndex] = skipFrames;
1206 
1207 			if (Settings.TurboMode)
1208 			{
1209 				drawnFrames[tableIndex] = (drawnFrames[tableIndex] + (macFastForwardRate / 2)) / macFastForwardRate;
1210 				if (drawnFrames[tableIndex] == 0)
1211 					drawnFrames[tableIndex] = 1;
1212 			}
1213 
1214 			tableIndex = (tableIndex + 1) % 60;
1215 
1216 			for (int i = 0; i < 60; i++)
1217 				frameCalc += drawnFrames[i];
1218 
1219 			IPPU.DisplayedRenderedFrameCount = (Memory.ROMFramesPerSecond * 60) / frameCalc;
1220 		}
1221 	}
1222 
1223 	switch (drawingMethod)
1224 	{
1225 		case kDrawingOpenGL:
1226 			S9xPutImageOpenGL(width, height);
1227 			break;
1228 
1229 		case kDrawingBlitGL:
1230 			S9xPutImageBlitGL(width, height);
1231 			break;
1232 	}
1233 }
1234 
S9xPutImageOpenGL(int width,int height)1235 static void S9xPutImageOpenGL (int width, int height)
1236 {
1237 	int	orig_height = height;
1238 
1239 	if ((imageWidth[0] != width) || (imageHeight[0] != height))
1240 		windowResizeCount += 2;
1241 
1242 	if (windowResizeCount > 0)
1243 	{
1244 		if (drawoverscan && (height % SNES_HEIGHT == 0))
1245 		{
1246 			int		pitch    = width << 1;
1247 			int		extbtm   = (height > 256) ? (SNES_HEIGHT_EXTENDED << 1) : SNES_HEIGHT_EXTENDED;
1248 			uint32	*extarea = (uint32 *) ((uint8 *) GFX.Screen + height * pitch);
1249 
1250 			for (int i = 0; i < (((extbtm - height) * pitch) >> 2); i++)
1251 				extarea[i] = 0;
1252 
1253 			height = extbtm;
1254 		}
1255 
1256 		int	vh = (height > 256) ? height : (height << 1);
1257 
1258 		if (fullscreen)
1259 		{
1260 			CGLSetCurrentContext(glContext);
1261 
1262 			glViewport(0, 0, glScreenW, glScreenH);
1263 			glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1264 			glClear(GL_COLOR_BUFFER_BIT);
1265 
1266 			if (glstretch)
1267 			{
1268 				float   fpw = (float) glScreenH / vh * 512.0f;
1269 				int		pw  = (int) (fpw + ((float) glScreenW - fpw) * (float) macAspectRatio / 10000.0);
1270 
1271 				glViewport((glScreenW - pw) >> 1, 0, pw, glScreenH);
1272 			}
1273 			else
1274 				glViewport((glScreenW - 512) >> 1, (glScreenH - vh) >> 1, 512, vh);
1275 		}
1276 		else
1277 		{
1278 			int	ww = (int) gWindowRect.size.width,
1279 				wh = (int) gWindowRect.size.height;
1280 
1281 			aglSetCurrentContext(agContext);
1282 			aglUpdateContext(agContext);
1283 
1284 			glViewport(0, 0, ww, wh);
1285 			glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1286 			glClear(GL_COLOR_BUFFER_BIT);
1287 
1288 			if (windowExtend)
1289 				glViewport(0, ((kMacWindowHeight - vh) >> 1) * wh / kMacWindowHeight, ww, vh * wh / kMacWindowHeight);
1290 		}
1291 
1292 		glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1293 
1294 		if (!ciFilterEnable)
1295 		{
1296 			textureNum = (width <= 256) ? ((height <= 256) ? kGL256256 : kGL256512) : ((height <= 256) ? kGL512256 : kGL512512);
1297 			OpenGL.vertex[textureNum][5] = OpenGL.vertex[textureNum][7] = OpenGL.rangeExt ? height : (vh / 512.0f);
1298 			glBindTexture(OpenGL.target, OpenGL.textures[textureNum]);
1299 		}
1300 		else
1301 		{
1302 			glMatrixMode(GL_PROJECTION);
1303 			glLoadIdentity();
1304 			glOrtho(0, width, orig_height - height, orig_height, -1, 1);
1305 
1306 			if (cgGameImage)
1307 				CGImageRelease(cgGameImage);
1308 			cgGameImage = CreateGameScreenCGImage();
1309 		}
1310 
1311 		imageWidth[0]  = width;
1312 		imageHeight[0] = height;
1313 
1314 		windowResizeCount--;
1315 	}
1316 	else
1317 	{
1318 		if (drawoverscan)
1319 			height = (height > 256) ? (SNES_HEIGHT_EXTENDED << 1) : SNES_HEIGHT_EXTENDED;
1320 	}
1321 
1322 	if (!ciFilterEnable)
1323 	{
1324 		glTexSubImage2D(OpenGL.target, 0, 0, 0, OpenGL.texW[textureNum], OpenGL.texH[textureNum], OpenGL.format, OpenGL.type, GFX.Screen);
1325 
1326 		if (!screencurvature)
1327 		{
1328 			glBegin(GL_QUADS);
1329 
1330 			glTexCoord2fv(&OpenGL.vertex[textureNum][6]);
1331 			glVertex2f(-1.0f, -1.0f);
1332 			glTexCoord2fv(&OpenGL.vertex[textureNum][4]);
1333 			glVertex2f( 1.0f, -1.0f);
1334 			glTexCoord2fv(&OpenGL.vertex[textureNum][2]);
1335 			glVertex2f( 1.0f,  1.0f);
1336 			glTexCoord2fv(&OpenGL.vertex[textureNum][0]);
1337 			glVertex2f(-1.0f,  1.0f);
1338 
1339 			glEnd();
1340 		}
1341 		else
1342 		{
1343 			GLfloat *t, *s;
1344 
1345 			t = scTexArray[(height % SNES_HEIGHT) ? kSC2xExtend : kSC2xNormal];
1346 			s = scScnArray;
1347 
1348 			for (int i = 0; i < kSCMeshY; i++)
1349 			{
1350 				glTexCoordPointer(2, GL_FLOAT, 0, t);
1351 				glVertexPointer(3, GL_FLOAT, 0, s);
1352 				glDrawArrays(GL_TRIANGLE_STRIP, 0, (kSCMeshX + 1) * 2);
1353 
1354 				t += (kSCMeshX + 1) * 2 * 2;
1355 				s += (kSCMeshX + 1) * 2 * 3;
1356 			}
1357 		}
1358 
1359 		glFinishObjectAPPLE(GL_TEXTURE, OpenGL.textures[textureNum]);
1360 	}
1361 	else
1362 	{
1363 		CGRect	src;
1364 
1365 		src = CGRectMake(0, 0, width, orig_height);
1366 		DrawWithCoreImageFilter(src, cgGameImage);
1367 	}
1368 
1369 	if (fullscreen)
1370 		CGLFlushDrawable(glContext);
1371 	else
1372 		aglSwapBuffers(agContext);
1373 }
1374 
S9xPutImageBlitGL(int width,int height)1375 static void S9xPutImageBlitGL (int width, int height)
1376 {
1377 	Blitter	blitFn;
1378 	int		copyWidth, copyHeight;
1379 
1380 	if ((imageWidth[whichBuf] != width) || (imageHeight[whichBuf] != height))
1381 	{
1382 		if ((videoMode == VIDEOMODE_TV) && (width <= 256))
1383 			S9xBlitClearDelta();
1384 
1385 		if (drawoverscan && (height % SNES_HEIGHT == 0))
1386 		{
1387 			memset(blitGLBuffer, 0, 1024 * 1024 * 2);
1388 
1389 			int		pitch    = width << 1;
1390 			int		extbtm   = (height > 256) ? (SNES_HEIGHT_EXTENDED << 1) : SNES_HEIGHT_EXTENDED;
1391 			uint32	*extarea = (uint32 *) ((uint8 *) GFX.Screen + height * pitch);
1392 
1393 			for (int i = 0; i < (((extbtm - height) * pitch) >> 2); i++)
1394 				extarea[i] = 0;
1395 
1396 			height = extbtm;
1397 		}
1398 	}
1399 	else
1400 	{
1401 		if (drawoverscan)
1402 			height = (height > 256) ? (SNES_HEIGHT_EXTENDED << 1) : SNES_HEIGHT_EXTENDED;
1403 	}
1404 
1405 	switch (nx)
1406 	{
1407 		default:
1408 		case 2:
1409 			if (videoMode == VIDEOMODE_BLEND)
1410 			{
1411 				if (width <= 256)
1412 				{
1413 					copyWidth  = width  * 2;
1414 					copyHeight = height;
1415 					blitFn = S9xBlitPixBlend2x1;
1416 				}
1417 				else
1418 				{
1419 					copyWidth  = width;
1420 					copyHeight = height;
1421 					blitFn = S9xBlitPixBlend1x1;
1422 				}
1423 			}
1424 			else
1425 			if (height <= 256)
1426 			{
1427 				if (width <= 256)
1428 				{
1429 					copyWidth  = width  * 2;
1430 					copyHeight = height * 2;
1431 
1432 					switch (videoMode)
1433 					{
1434 						default:
1435 						case VIDEOMODE_TV:			blitFn = S9xBlitPixTV2x2;			break;
1436 						case VIDEOMODE_SUPEREAGLE:	blitFn = S9xBlitPixSuperEagle16;	break;
1437 						case VIDEOMODE_2XSAI:		blitFn = S9xBlitPix2xSaI16;			break;
1438 						case VIDEOMODE_SUPER2XSAI:	blitFn = S9xBlitPixSuper2xSaI16;	break;
1439 						case VIDEOMODE_EPX:			blitFn = S9xBlitPixEPX16;			break;
1440 						case VIDEOMODE_HQ2X:		blitFn = S9xBlitPixHQ2x16;			break;
1441 					}
1442 				}
1443 				else
1444 				{
1445 					if (videoMode == VIDEOMODE_TV)
1446 					{
1447 						copyWidth  = width;
1448 						copyHeight = height * 2;
1449 						blitFn = S9xBlitPixTV1x2;
1450 					}
1451 					else
1452 					{
1453 						copyWidth  = width;
1454 						copyHeight = height;
1455 						blitFn = S9xBlitPixSimple1x1;
1456 					}
1457 				}
1458 			}
1459 			else
1460 			{
1461 				copyWidth  = width;
1462 				copyHeight = height;
1463 				blitFn = S9xBlitPixSimple1x1;
1464 			}
1465 
1466 			break;
1467 
1468 		case 3:
1469 			if (width <= 256 && height <= 256)
1470 			{
1471 				copyWidth  = width  * 3;
1472 				copyHeight = height * 3;
1473 				blitFn = S9xBlitPixHQ3x16;
1474 			}
1475 			else
1476 			{
1477 				copyWidth  = width;
1478 				copyHeight = height;
1479 				blitFn = S9xBlitPixSimple1x1;
1480 			}
1481 
1482 			break;
1483 
1484 		case 4:
1485 			if (width <= 256 && height <= 256)
1486 			{
1487 				copyWidth  = width  * 4;
1488 				copyHeight = height * 4;
1489 				blitFn = S9xBlitPixHQ4x16;
1490 			}
1491 			else
1492 			if (width >  256 && height  > 256)
1493 			{
1494 				copyWidth  = width  * 2;
1495 				copyHeight = height * 2;
1496 				blitFn = S9xBlitPixHQ2x16;
1497 			}
1498 			else
1499 			{
1500 				copyWidth  = width;
1501 				copyHeight = height;
1502 				blitFn = S9xBlitPixSimple1x1;
1503 			}
1504 
1505 			break;
1506 
1507 		case -1:
1508 		case -2:
1509 			copyWidth  = ntsc_width;
1510 			copyHeight = height;
1511 
1512 			if (width <= 256)
1513 				blitFn = S9xBlitPixNTSC16;
1514 			else
1515 				blitFn = S9xBlitPixHiResNTSC16;
1516 
1517 			break;
1518 	}
1519 
1520 	imageWidth[whichBuf]  = width;
1521 	imageHeight[whichBuf] = height;
1522 
1523 	if (multiprocessor)
1524 	{
1525 		MPWaitOnSemaphore(readySemaphore, kDurationForever);
1526 
1527 		mpBlit->nx          = nx;
1528 		mpBlit->blitFn      = blitFn;
1529 		mpBlit->srcWidth    = width;
1530 		mpBlit->srcHeight   = height;
1531 		mpBlit->copyWidth   = copyWidth;
1532 		mpBlit->copyHeight  = copyHeight;
1533 		mpBlit->gfxBuffer   = GFX.Screen;
1534 
1535 		MPNotifyQueue(taskQueue, (void *) kMPBlitFrame, 0, 0);
1536 
1537 		whichBuf = 1 - whichBuf;
1538 		GFX.Screen = gfxScreen[whichBuf];
1539 	}
1540 	else
1541 		RenderBlitScreen(blitFn, nx, width, height, copyWidth, copyHeight, GFX.Screen);
1542 }
1543 
S9xPutImageBlitGL2(int blit_width,int blit_height)1544 static void S9xPutImageBlitGL2 (int blit_width, int blit_height)
1545 {
1546 	if ((prevBlitWidth != blit_width) || (prevBlitHeight != blit_height))
1547 		windowResizeCount += 2;
1548 
1549 	if (windowResizeCount > 0)
1550 	{
1551 		if (fullscreen)
1552 		{
1553 			CGLSetCurrentContext(glContext);
1554 
1555 			glViewport(0, 0, glScreenW, glScreenH);
1556 			glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1557 			glClear(GL_COLOR_BUFFER_BIT);
1558 
1559 			if (glstretch)
1560 			{
1561 				int		sh  = (blit_width < blit_height) ? (blit_height >> 1) : ((blit_width > blit_height * 2) ? (blit_height << 1) : blit_height);
1562 				float	fpw = (float) glScreenH / (float) sh * (float) blit_width;
1563 				int		pw  = (int) (fpw + ((float) glScreenW - fpw) * (float) macAspectRatio / 10000.0);
1564 
1565 				glViewport((glScreenW - pw) >> 1, 0, pw, glScreenH);
1566 			}
1567 			else
1568 			{
1569 				int		sw, sh;
1570 
1571 				if (nx < 0)
1572 				{
1573 					sw = ntsc_width;
1574 					sh = ((blit_height % SNES_HEIGHT) ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT) * 2;
1575 				}
1576 				else
1577 				{
1578 					sw = SNES_WIDTH * nx;
1579 					sh = ((blit_height % SNES_HEIGHT) ? SNES_HEIGHT_EXTENDED : SNES_HEIGHT) * nx;
1580 				}
1581 
1582 				glViewport((glScreenW - sw) >> 1, (glScreenH - sh) >> 1, sw, sh);
1583 			}
1584 		}
1585 		else
1586 		{
1587 			int	ww = (int) gWindowRect.size.width,
1588 				wh = (int) gWindowRect.size.height;
1589 
1590 			aglSetCurrentContext(agContext);
1591 			aglUpdateContext(agContext);
1592 
1593 			glViewport(0, 0, ww, wh);
1594 			glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1595 			glClear(GL_COLOR_BUFFER_BIT);
1596 
1597 			if (windowExtend)
1598 			{
1599 				int	bh = (blit_height % SNES_HEIGHT) ? (SNES_HEIGHT_EXTENDED << 1) : (SNES_HEIGHT << 1);
1600 				glViewport(0, ((kMacWindowHeight - bh) >> 1) * wh / kMacWindowHeight, ww, bh * wh / kMacWindowHeight);
1601 			}
1602 		}
1603 
1604 		if (!ciFilterEnable)
1605 		{
1606 			if (nx < 0)
1607 				textureNum = (blit_height > 256) ? kGLNTS512 : kGLNTS256;
1608 			else
1609 			{
1610 				switch (blit_width / SNES_WIDTH)
1611 				{
1612 					default:
1613 					case 1:
1614 					case 2:	textureNum = kGLBlit2x;	break;
1615 					case 3:	textureNum = kGLBlit3x;	break;
1616 					case 4:	textureNum = kGLBlit4x;	break;
1617 				}
1618 			}
1619 
1620 			if (nx < 0)
1621 			{
1622 				int	sh = (blit_height > 256) ?  512 : 256;
1623 				OpenGL.vertex[textureNum][2] = OpenGL.vertex[textureNum][4] = blit_width  / 1024.0f;
1624 				OpenGL.vertex[textureNum][5] = OpenGL.vertex[textureNum][7] = blit_height / (float) sh;
1625 				glPixelStorei(GL_UNPACK_ROW_LENGTH, 1024);
1626 			}
1627 			else
1628 			{
1629 				if (OpenGL.rangeExt)
1630 				{
1631 					OpenGL.vertex[textureNum][2] = OpenGL.vertex[textureNum][4] = blit_width;
1632 					OpenGL.vertex[textureNum][5] = OpenGL.vertex[textureNum][7] = blit_height;
1633 					glPixelStorei(GL_UNPACK_ROW_LENGTH, blit_width);
1634 				}
1635 				else
1636 				{
1637 					int	sl = (blit_width  > 512) ? 1024 : 512;
1638 					int	sh = (blit_height > 512) ? 1024 : 512;
1639 					OpenGL.vertex[textureNum][2] = OpenGL.vertex[textureNum][4] = blit_width  / (float) sl;
1640 					OpenGL.vertex[textureNum][5] = OpenGL.vertex[textureNum][7] = blit_height / (float) sh;
1641 					glPixelStorei(GL_UNPACK_ROW_LENGTH, (blit_width > 512) ? 1024 : ((blit_width > 256) ? 512 : 256));
1642 				}
1643 			}
1644 
1645 			glBindTexture(OpenGL.target, OpenGL.textures[textureNum]);
1646 		}
1647 		else
1648 		{
1649 			int	sl = OpenGL.rangeExt ? blit_width : ((blit_width > 512) ? 1024 : ((blit_width > 256) ? 512 : 256));
1650 
1651 			glPixelStorei(GL_UNPACK_ROW_LENGTH, sl);
1652 			glMatrixMode(GL_PROJECTION);
1653 			glLoadIdentity();
1654 			glOrtho(0, blit_width, 0, blit_height, -1, 1);
1655 
1656 			if (cgBlitImage)
1657 				CGImageRelease(cgBlitImage);
1658 			cgBlitImage = CreateBlitScreenCGImage(blit_width, blit_height, sl << 1, blitGLBuffer);
1659 		}
1660 
1661 		prevBlitWidth  = blit_width;
1662 		prevBlitHeight = blit_height;
1663 
1664 		windowResizeCount--;
1665 	}
1666 
1667 	if (!ciFilterEnable)
1668 	{
1669 		glTexSubImage2D(OpenGL.target, 0, 0, 0, OpenGL.texW[textureNum], OpenGL.texH[textureNum], OpenGL.format, OpenGL.type, blitGLBuffer);
1670 
1671 		if (!screencurvature)
1672 		{
1673 			glBegin(GL_QUADS);
1674 
1675 			glTexCoord2fv(&OpenGL.vertex[textureNum][6]);
1676 			glVertex2f(-1.0f, -1.0f);
1677 			glTexCoord2fv(&OpenGL.vertex[textureNum][4]);
1678 			glVertex2f( 1.0f, -1.0f);
1679 			glTexCoord2fv(&OpenGL.vertex[textureNum][2]);
1680 			glVertex2f( 1.0f,  1.0f);
1681 			glTexCoord2fv(&OpenGL.vertex[textureNum][0]);
1682 			glVertex2f(-1.0f,  1.0f);
1683 
1684 			glEnd();
1685 		}
1686 		else
1687 		{
1688 			GLfloat *t, *s;
1689 			int		tex;
1690 
1691 			if (nx < 0)
1692 				tex = (blit_height % SNES_HEIGHT) ? kSCNTExtend : kSCNTNormal;
1693 			else
1694 			if (blit_width > blit_height * 2)
1695 			{
1696 				if (blit_width / SNES_WIDTH != 3)
1697 					tex = (blit_height % SNES_HEIGHT) ? kSC2xEHiRes : kSC2xNHiRes;
1698 				else
1699 					tex = (blit_height % SNES_HEIGHT) ? kSC3xEHiRes : kSC3xNHiRes;
1700 			}
1701 			else
1702 			if (blit_width > blit_height)
1703 			{
1704 				if (blit_width / SNES_WIDTH != 3)
1705 					tex = (blit_height % SNES_HEIGHT) ? kSC2xExtend : kSC2xNormal;
1706 				else
1707 					tex = (blit_height % SNES_HEIGHT) ? kSC3xExtend : kSC3xNormal;
1708 			}
1709 			else
1710 				tex = (blit_height % SNES_HEIGHT) ? kSC2xEInter : kSC2xNInter;
1711 
1712 			t = scTexArray[tex];
1713 			s = scScnArray;
1714 
1715 			for (int i = 0; i < kSCMeshY; i++)
1716 			{
1717 				glTexCoordPointer(2, GL_FLOAT, 0, t);
1718 				glVertexPointer(3, GL_FLOAT, 0, s);
1719 				glDrawArrays(GL_TRIANGLE_STRIP, 0, (kSCMeshX + 1) * 2);
1720 
1721 				t += (kSCMeshX + 1) * 2 * 2;
1722 				s += (kSCMeshX + 1) * 2 * 3;
1723 			}
1724 		}
1725 
1726 		glFinishObjectAPPLE(GL_TEXTURE, OpenGL.textures[textureNum]);
1727 	}
1728 	else
1729 	{
1730 		CGRect	src;
1731 
1732 		src = CGRectMake(0, 0, blit_width, blit_height);
1733 		DrawWithCoreImageFilter(src, cgBlitImage);
1734 	}
1735 
1736 	if (fullscreen)
1737 		CGLFlushDrawable(glContext);
1738 	else
1739 		aglSwapBuffers(agContext);
1740 }
1741 
S9xTextMode(void)1742 void S9xTextMode (void)
1743 {
1744 	return;
1745 }
1746 
S9xGraphicsMode(void)1747 void S9xGraphicsMode (void)
1748 {
1749 	return;
1750 }
1751 
S9xSetPalette(void)1752 void S9xSetPalette (void)
1753 {
1754 	return;
1755 }
1756