1 /*
2  * Copyright 2014-2017, Björn Ståhl
3  * License: 3-Clause BSD, see COPYING file in arcan source repository.
4  * Reference: http://arcan-fe.com
5  */
6 
7 /*
8  * PLATFORM DRIVER NOTICE:
9  * This platform driver is incomplete in the sense that it was only set
10  * up in order to allow for headless LWA/hijack/retro3d.
11  *
12  * Note that we can probably get decent working buffer passing without
13  * readbacks here using IOSurface, see the serverOpenGLView.m
14  */
15 
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <stdint.h>
20 #include <stdbool.h>
21 #include <math.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <dlfcn.h>
27 
28 #include "arcan_math.h"
29 #include "arcan_general.h"
30 #include "arcan_video.h"
31 #include "arcan_videoint.h"
32 
33 #ifndef PLATFORM_SUFFIX
34 #define PLATFORM_SUFFIX platform
35 #endif
36 
37 #define MERGE(X,Y) X ## Y
38 #define EVAL(X,Y) MERGE(X,Y)
39 #define PLATFORM_SYMBOL(fun) EVAL(PLATFORM_SUFFIX, fun)
40 
41 #include <OpenGL/OpenGL.h>
42 #include <OpenGL/GL.h>
43 
44 static char* darwin_synchopts[] = {
45 	"default", "driver- specific GL swap",
46 	NULL
47 };
48 
49 static char* darwin_envopts[] = {
50 	NULL
51 };
52 
53 static struct {
54 	size_t mdispw, mdisph;
55 	size_t canvasw, canvash;
56 } darwin;
57 
58 static CGLContextObj context;
59 
PLATFORM_SYMBOL(_video_init)60 bool PLATFORM_SYMBOL(_video_init)(uint16_t w, uint16_t h,
61 	uint8_t bpp, bool fs, bool frames, const char* cap)
62 {
63 	CGLPixelFormatObj pix;
64 	CGLError errorCode;
65 	GLint num;
66 
67 	CGLPixelFormatAttribute attributes[4] = {
68   	kCGLPFAAccelerated,
69   	kCGLPFAOpenGLProfile,
70   	(CGLPixelFormatAttribute) kCGLOGLPVersion_Legacy,
71   	(CGLPixelFormatAttribute) 0
72 	};
73 
74 	errorCode = CGLChoosePixelFormat( attributes, &pix, &num );
75   errorCode = CGLCreateContext( pix, NULL, &context );
76 	CGLDestroyPixelFormat( pix );
77   errorCode = CGLSetCurrentContext( context );
78 
79 /*
80  * no double buffering,
81  * we let the parent transfer process act as the limiting clock.
82  */
83 	GLint si = 0;
84 	CGLSetParameter(context, kCGLCPSwapInterval, &si);
85 
86 	darwin.mdispw = darwin.canvasw = w;
87 	darwin.mdisph = darwin.canvash = h;
88 
89 	return true;
90 }
91 
92 size_t platform_nupd;
PLATFORM_SYMBOL(_video_synch)93 void PLATFORM_SYMBOL(_video_synch)(uint64_t tick_count, float fract,
94 	video_synchevent pre, video_synchevent post)
95 {
96 	if (pre)
97 		pre();
98 
99 #ifndef HEADLESS_NOARCAN
100 	arcan_bench_register_cost( arcan_vint_refresh(fract, &platform_nupd) );
101 
102 	agp_activate_rendertarget(NULL);
103 
104 	arcan_vint_drawrt(arcan_vint_world(), 0, 0,
105 		darwin.mdispw, darwin.mdisph);
106 	arcan_vint_drawcursor(false);
107 #endif
108 
109 	glFlush();
110 
111 	if (post)
112 		post();
113 }
114 
PLATFORM_SYMBOL(_map_buffer)115 bool PLATFORM_SYMBOL(_map_buffer)(
116 	struct agp_vstore* vs, struct agp_buffer_plane* planes, size_t n)
117 {
118 	return false;
119 }
120 
PLATFORM_SYMBOL(_video_decay)121 size_t PLATFORM_SYMBOL(_video_decay){
122 	return 0;
123 }
124 
PLATFORM_SYMBOL(_video_dpms)125 enum dpms_state PLATFORM_SYMBOL(_video_dpms)(
126 	platform_display_id disp, enum dpms_state state)
127 {
128 	return ADPMS_ON;
129 }
130 
PLATFORM_SYMBOL(_video_query_modes)131 struct monitor_mode* PLATFORM_SYMBOL(_video_query_modes)(
132 	platform_display_id id, size_t* count)
133 {
134 	static struct monitor_mode mode = {};
135 
136 	mode.width  = darwin.canvasw;
137 	mode.height = darwin.canvash;
138 	mode.depth  = sizeof(av_pixel) * 8;
139 	mode.refresh = 60; /* should be queried */
140 	*count = 1;
141 
142 	return &mode;
143 }
144 
PLATFORM_SYMBOL(_video_dimensions)145 struct monitor_mode PLATFORM_SYMBOL(_video_dimensions)()
146 {
147 	struct monitor_mode res = {
148 		.width = darwin.canvasw,
149 		.height = darwin.canvash,
150 		.phy_width = darwin.mdispw,
151 		.phy_height = darwin.mdisph
152 	};
153 	return res;
154 }
155 
PLATFORM_SYMBOL(_video_auth)156 bool PLATFORM_SYMBOL(_video_auth)(int cardn, unsigned token)
157 {
158 	return false;
159 }
160 
PLATFORM_SYMBOL(_video_map_handle)161 bool PLATFORM_SYMBOL(_video_map_handle)(
162 	struct agp_vstore* dst, int64_t handle)
163 {
164 	return false;
165 }
166 
PLATFORM_SYMBOL(_video_specify_mode)167 bool PLATFORM_SYMBOL(_video_specify_mode)(platform_display_id id,
168 	struct monitor_mode mode)
169 {
170 	return false;
171 }
172 
PLATFORM_SYMBOL(_video_synchopts)173 const char** PLATFORM_SYMBOL(_video_synchopts)(void)
174 {
175 	return (const char**) darwin_synchopts;
176 }
177 
PLATFORM_SYMBOL(_video_envopts)178 const char** PLATFORM_SYMBOL(_video_envopts)(void)
179 {
180 	return (const char**) darwin_envopts;
181 }
182 
PLATFORM_SYMBOL(_video_setsynch)183 void PLATFORM_SYMBOL(_video_setsynch)(const char* arg)
184 {
185 	arcan_warning("unhandled synchronization strategy (%s) ignored.\n", arg);
186 }
187 
PLATFORM_SYMBOL(_video_prepare_external)188 void PLATFORM_SYMBOL(_video_prepare_external) () {}
PLATFORM_SYMBOL(_video_restore_external)189 void PLATFORM_SYMBOL(_video_restore_external) () {}
190 
PLATFORM_SYMBOL(_video_shutdown)191 void PLATFORM_SYMBOL(_video_shutdown) ()
192 {
193 }
194 
PLATFORM_SYMBOL(_video_display_edid)195 bool PLATFORM_SYMBOL(_video_display_edid)(platform_display_id did,
196 	char** out, size_t* sz)
197 {
198 	*out = NULL;
199 	*sz = 0;
200 	return false;
201 }
202 
PLATFORM_SYMBOL(_video_displays)203 size_t PLATFORM_SYMBOL(_video_displays)(platform_display_id* dids, size_t* lim)
204 {
205 	if (dids && lim && *lim > 0){
206 		dids[0] = 0;
207 	}
208 
209 	return 1;
210 }
211 
PLATFORM_SYMBOL(_video_gfxsym)212 void* PLATFORM_SYMBOL(_video_gfxsym)(const char* sym)
213 {
214 	static void* dlh = NULL;
215   if (NULL == dlh)
216     dlh = dlopen("/System/Library/Frameworks/"
217 			"OpenGL.framework/Versions/Current/OpenGL", RTLD_LAZY);
218 
219   return dlh ? dlsym(dlh, sym) : NULL;
220 }
221 
PLATFORM_SYMBOL(_video_capstr)222 const char* PLATFORM_SYMBOL(_video_capstr)(void)
223 {
224 	static char* capstr;
225 
226 	if (!capstr){
227 		const char* vendor = (const char*) glGetString(GL_VENDOR);
228 		const char* render = (const char*) glGetString(GL_RENDERER);
229 		const char* version = (const char*) glGetString(GL_VERSION);
230 		const char* shading = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);
231 		const char* exts = (const char*) glGetString(GL_EXTENSIONS);
232 
233 		size_t interim_sz = 64 * 1024;
234 		char* interim = malloc(interim_sz);
235 		size_t nw = snprintf(interim, interim_sz, "Video Platform (LWA-Darwin)\n"
236 			"Vendor: %s\nRenderer: %s\nGL Version: %s\n"
237 			"GLSL Version: %s\n\n Extensions Supported: \n%s\n\n",
238 			vendor, render, version, shading, exts
239 		) + 1;
240 
241 		if (nw < (interim_sz >> 1)){
242 			capstr = malloc(nw);
243 			memcpy(capstr, interim, nw);
244 			free(interim);
245 		}
246 		else
247 			capstr = interim;
248 	}
249 
250 	return capstr;
251 }
252 
PLATFORM_SYMBOL(_video_minimize)253 void PLATFORM_SYMBOL(_video_minimize) () {}
254 
255