1
2
3 /*
4 * Argyll Color Correction System
5 * Web Display target patch window
6 *
7 * Author: Graeme W. Gill
8 * Date: 3/4/12
9 *
10 * Copyright 2013 Graeme W. Gill
11 * All rights reserved.
12 *
13 * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
14 * see the License.txt file for licencing details.
15 */
16
17 #include <stdio.h>
18 #include <string.h>
19 #ifdef NT
20 # include <winsock2.h>
21 # include <shlwapi.h>
22 #endif
23 #include "copyright.h"
24 #include "aconfig.h"
25 #include "icc.h"
26 #include "numsup.h"
27 #include "cgats.h"
28 #include "conv.h"
29 #include "dispwin.h"
30 #include "madvrwin.h"
31 #include "conv.h"
32 #include "mongoose.h"
33
34 #define ENABLE_RAMDAC
35
36 #undef DEBUG
37 //#define STANDALONE_TEST
38
39 #ifdef DEBUG
40 #define errout stderr
41 # define debug(xx) fprintf(errout, xx )
42 # define debug2(xx) fprintf xx
43 # define debugr(xx) fprintf(errout, xx )
44 # define debugr2(xx) fprintf xx
45 # define debugrr(xx) fprintf(errout, xx )
46 # define debugrr2(xx) fprintf xx
47 # define debugrr2l(lev, xx) fprintf xx
48 #else
49 #define errout stderr
50 # define debug(xx)
51 # define debug2(xx)
52 # define debugr(xx) if (p->ddebug) fprintf(errout, xx )
53 # define debugr2(xx) if (p->ddebug) fprintf xx
54 # define debugrr(xx) if (callback_ddebug) fprintf(errout, xx )
55 # define debugrr2(xx) if (callback_ddebug) fprintf xx
56 # define debugrr2l(lev, xx) if (callback_ddebug >= lev) fprintf xx
57 #endif
58
59 /* ----------------------------------------------- */
60 /* MadVR functions */
61
62 #ifndef KEY_WOW64_32KEY
63 # define KEY_WOW64_32KEY (0x0200)
64 #endif
65
66 /* Incase shlwapi.h doesn't declare this */
67 #include <pshpack1.h>
68 typedef struct _ADLLVERSIONINFO2
69 {
70 DLLVERSIONINFO info1;
71 DWORD dwFlags;
72 ULONGLONG ullVersion;
73 } ADLLVERSIONINFO2;
74 #include <poppack.h>
75
76 HMODULE HcNetDll = NULL;
77 BOOL (WINAPI *madVR_BlindConnect)(BOOL searchLan, DWORD timeOut) = NULL;
78 BOOL (WINAPI *madVR_GetVersion)(DWORD *version);
79 BOOL (WINAPI *madVR_SetOsdText)(LPCWSTR text);
80 BOOL (WINAPI *madVR_Disable3dlut)() = NULL;
81 BOOL (WINAPI *madVR_GetDeviceGammaRamp)(LPVOID ramp) = NULL;
82 BOOL (WINAPI *madVR_SetDeviceGammaRamp)(LPVOID ramp) = NULL;
83 BOOL (WINAPI *madVR_GetPatternConfig)(int *patternAreaInPercent, int *backgroundLevelInPercent,
84 int *backgroundMode, int *blackBorderWidth) = NULL;
85 BOOL (WINAPI *madVR_SetPatternConfig)(int patternAreaInPercent, int backgroundLevelInPercent,
86 int backgroundMode, int blackBorderWidth) = NULL;
87 BOOL (WINAPI *madVR_ShowRGB)(double r, double g, double b) = NULL;
88 BOOL (WINAPI *madVR_SetProgressBarPos)(int currentPos, int maxPos);
89 BOOL (WINAPI *madVR_Disconnect)() = NULL;
90
91 /* Locate and populate the MadVR functions */
92 /* Return NZ on failure */
initMadVR(dispwin * p)93 static int initMadVR(dispwin *p) {
94 wchar_t *dllname;
95 WCHAR modname[MAX_PATH];
96 DWORD hnd;
97 DWORD len = 0;
98 WORD v1 = 0, v2 = 0, v3 = 0, v4 = 0; /* MadVR version */
99
100 if (sizeof(dllname) > 4) /* Compiled as 64 bit */
101 dllname = L"madHcNet64.dll";
102 else
103 dllname = L"madHcNet32.dll";
104
105 if ((HcNetDll = LoadLibraryW(dllname)) == NULL) {
106 HKEY hk1;
107 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"CLSID\\{E1A8B82A-32CE-4B0D-BE0D-AA68C772E423}\\InprocServer32", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &hk1) == ERROR_SUCCESS) {
108 DWORD size;
109 LPWSTR us1;
110 int i1;
111 size = MAX_PATH * 2 + 2;
112 us1 = (LPWSTR) LocalAlloc(LPTR, size + 20);
113 i1 = RegQueryValueExW(hk1, NULL, NULL, NULL, (LPBYTE) us1, &size);
114 if (i1 == ERROR_MORE_DATA) {
115 LocalFree(us1);
116 us1 = (LPWSTR) LocalAlloc(LPTR, size + 20);
117 i1 = RegQueryValueExW(hk1, NULL, NULL, NULL, (LPBYTE) us1, &size);
118 }
119 if (i1 == ERROR_SUCCESS) {
120 for (i1 = lstrlenW(us1) - 2; i1 > 0; i1--)
121 if (us1[i1] == L'\\') {
122 us1[i1 + 1] = 0;
123 break;
124 }
125 wcscat(us1, dllname);
126 HcNetDll = LoadLibraryW(us1);
127 }
128 LocalFree(us1);
129 RegCloseKey(hk1);
130 }
131 }
132 if (HcNetDll != NULL) {
133 HRESULT (WINAPI *dllgetver)(ADLLVERSIONINFO2 *) = NULL;
134
135 *(FARPROC*)&dllgetver = GetProcAddress(HcNetDll, "DllGetVersion");
136
137 if (dllgetver != NULL) {
138 ADLLVERSIONINFO2 ver;
139
140 ver.info1.cbSize = sizeof(ADLLVERSIONINFO2);
141 dllgetver(&ver);
142
143 v1 = 0xffff & (ver.ullVersion >> 48);
144 v2 = 0xffff & (ver.ullVersion >> 32);
145 v3 = 0xffff & (ver.ullVersion >> 16);
146 v4 = 0xffff & ver.ullVersion;
147
148 } else {
149 debugr2((errout,"MadVR DllGetVersion failed - can't determine DLL version\n"));
150 }
151 }
152
153 if (HcNetDll != NULL) {
154 *(FARPROC*)&madVR_BlindConnect = GetProcAddress(HcNetDll, "madVR_BlindConnect");
155 *(FARPROC*)&madVR_GetVersion = GetProcAddress(HcNetDll, "madVR_GetVersion");
156 *(FARPROC*)&madVR_SetOsdText = GetProcAddress(HcNetDll, "madVR_SetOsdText");
157 *(FARPROC*)&madVR_Disable3dlut = GetProcAddress(HcNetDll, "madVR_Disable3dlut");
158 *(FARPROC*)&madVR_GetDeviceGammaRamp = GetProcAddress(HcNetDll, "madVR_GetDeviceGammaRamp");
159 *(FARPROC*)&madVR_SetDeviceGammaRamp = GetProcAddress(HcNetDll, "madVR_SetDeviceGammaRamp");
160 *(FARPROC*)&madVR_GetPatternConfig = GetProcAddress(HcNetDll, "madVR_GetPatternConfig");
161 *(FARPROC*)&madVR_SetPatternConfig = GetProcAddress(HcNetDll, "madVR_SetPatternConfig");
162 *(FARPROC*)&madVR_ShowRGB = GetProcAddress(HcNetDll, "madVR_ShowRGB");
163 *(FARPROC*)&madVR_SetProgressBarPos = GetProcAddress(HcNetDll, "madVR_SetProgressBarPos");
164 *(FARPROC*)&madVR_Disconnect = GetProcAddress(HcNetDll, "madVR_Disconnect");
165
166 if (madVR_BlindConnect
167 && madVR_GetVersion
168 && madVR_SetOsdText
169 && madVR_Disable3dlut
170 && madVR_GetDeviceGammaRamp
171 && madVR_SetDeviceGammaRamp
172 && madVR_GetPatternConfig
173 && madVR_SetPatternConfig
174 && madVR_ShowRGB
175 && madVR_SetProgressBarPos
176 && madVR_Disconnect) {
177 DWORD ver = 0;
178 /* Return value is unclear */
179 if (!madVR_GetVersion(&ver))
180 debugr2((errout,"MadVR_GetVersion failed - can't determine MadVR version\n"));
181
182 debugr2((errout,"Found all required functions in %ls V%d.%d.%d.%d MadVR V%x.%x.%x.%x functions\n",dllname,v1,v2,v3,v4, 0xff & (ver >> 24), 0xff & (ver >> 16), 0xff & (ver >> 8), 0xff & ver));
183 return 0;
184 }
185 debugr2((errout,"Failed to locate MadVR function in %ls %d.%d.%d.%d\n",dllname,v1,v2,v3,v4));
186 FreeLibrary(HcNetDll);
187 } else {
188 debugr2((errout,"Failed to load %ls\n",dllname));
189 }
190 return 1;
191 }
192
deinitMadVR(dispwin * p)193 static void deinitMadVR(dispwin *p) {
194 if (HcNetDll != NULL) {
195 FreeLibrary(HcNetDll);
196 HcNetDll = NULL;
197 }
198 }
199
200 /* ----------------------------------------------- */
201
202 /* Get RAMDAC values. ->del() when finished. */
203 /* Return NULL if not possible */
madvrwin_get_ramdac(dispwin * p)204 static ramdac *madvrwin_get_ramdac(dispwin *p) {
205 ramdac *r = NULL;
206
207 #ifdef ENABLE_RAMDAC
208 WORD vals[3][256]; /* 256 x 16 bit elements (Quantize) */
209 int i, j;
210
211 debugr("madvrwin_get_ramdac called\n");
212
213 /* Allocate a ramdac */
214 if ((r = (ramdac *)calloc(sizeof(ramdac), 1)) == NULL) {
215 debugr("madvrwin_get_ramdac failed on malloc()\n");
216 return NULL;
217 }
218 r->fdepth = p->fdepth;
219 r->rdepth = p->rdepth;
220 r->ndepth = p->ndepth;
221 r->nent = p->nent;
222
223 r->clone = dispwin_clone_ramdac;
224 r->setlin = dispwin_setlin_ramdac;
225 r->del = dispwin_del_ramdac;
226
227 for (j = 0; j < 3; j++) {
228
229 if ((r->v[j] = (double *)calloc(sizeof(double), r->nent)) == NULL) {
230 for (j--; j >= 0; j--)
231 free(r->v[j]);
232 free(r);
233 debugr("madvrwin_get_ramdac failed on malloc()\n");
234 return NULL;
235 }
236 }
237
238 /* GetDeviceGammaRamp() is hard coded for 3 x 256 entries (Quantize) */
239 if (r->nent != 256) {
240 free(r);
241 debugr2((errout,"GetDeviceGammaRamp() is hard coded for nent == 256, and we've got nent = %d!\n",r->nent));
242 return NULL;
243 }
244
245 if (!madVR_GetDeviceGammaRamp(vals)) {
246 free(r);
247 debugr2((errout,"madvrwin_get_ramdac failed on madVR_GetDeviceGammaRamp()\n"));
248 return NULL;
249 }
250
251 for (j = 0; j < 3; j++) {
252 for (i = 0; i < r->nent; i++) {
253 r->v[j][i] = vals[j][i]/65535.0;
254 }
255 }
256 #endif // ENABLE_RAMDAC
257 debugr2((errout,"madvrwin_get_ramdac returning 0x%x\n",r));
258
259 return r;
260 }
261
262 /* Set the RAMDAC values. */
263 /* Return nz if not possible */
madvrwin_set_ramdac(dispwin * p,ramdac * r,int persist)264 static int madvrwin_set_ramdac(dispwin *p, ramdac *r, int persist) {
265 int rv = 1;
266
267 #ifdef ENABLE_RAMDAC
268 int i, j;
269 WORD vals[3][256]; /* 16 bit elements */
270
271 debugr("madvrwin_set_ramdac called\n");
272
273 for (j = 0; j < 3; j++) {
274 for (i = 0; i < r->nent; i++) {
275 double vv = r->v[j][i];
276 if (vv < 0.0)
277 vv = 0.0;
278 else if (vv > 1.0)
279 vv = 1.0;
280 vals[j][i] = (int)(65535.0 * vv + 0.5);
281 }
282 }
283
284 if (!madVR_SetDeviceGammaRamp(vals)) {
285 debugr2((errout,"madvrwin_set_ramdac failed on madVR_SetDeviceGammaRamp()\n"));
286 rv = 1;
287 } else {
288 debugr("madvrwin_set_ramdac set\n");
289 rv = 0;
290 }
291 #endif // ENABLE_RAMDAC
292 return rv;
293 }
294
295 /* ----------------------------------------------- */
296 /* Install a display profile and make */
297 /* it the default for this display. */
298 /* Return nz if failed */
madvrwin_install_profile(dispwin * p,char * fname,ramdac * r,p_scope scope)299 int madvrwin_install_profile(dispwin *p, char *fname, ramdac *r, p_scope scope) {
300 debugr("madVRdisp doesn't support installing profiles\n");
301 return 1;
302 }
303
304 /* Un-Install a display profile */
305 /* Return nz if failed, */
madvrwin_uninstall_profile(dispwin * p,char * fname,p_scope scope)306 int madvrwin_uninstall_profile(dispwin *p, char *fname, p_scope scope) {
307 debugr("madVRdisp doesn't support uninstalling profiles\n");
308 return 1;
309 }
310
311 /* Get the currently installed display profile. */
312 /* Return NULL if failed. */
madvrwin_get_profile(dispwin * p,char * name,int mxlen)313 icmFile *madvrwin_get_profile(dispwin *p, char *name, int mxlen) {
314 debugr("madVRdisp doesn't support getting the current profile\n");
315 return NULL;
316 }
317
318 /* ----------------------------------------------- */
319
320 /* Change the window color. */
321 /* Return 1 on error, 2 on window being closed */
madvrwin_set_color(dispwin * p,double r,double g,double b)322 static int madvrwin_set_color(
323 dispwin *p,
324 double r, double g, double b /* Color values 0.0 - 1.0 */
325 ) {
326 int j;
327 double orgb[3]; /* Previous RGB value */
328 double kr, kf;
329 int update_delay = 0;
330
331 debugr("madvrwin_set_color called\n");
332
333 if (p->nowin)
334 return 1;
335
336 orgb[0] = p->rgb[0]; p->rgb[0] = r;
337 orgb[1] = p->rgb[1]; p->rgb[1] = g;
338 orgb[2] = p->rgb[2]; p->rgb[2] = b;
339
340 if (!madVR_ShowRGB(p->rgb[0], p->rgb[1], p->rgb[2])) {
341 debugr2((errout,"madVR_ShowRGB failed\n"));
342 return 1;
343 }
344
345 /* Allow for display update & instrument delays */
346 update_delay = dispwin_compute_delay(p, orgb);
347 debugr2((errout, "madvrwin_set_color delaying %d msec\n",update_delay));
348 msec_sleep(update_delay);
349
350 return 0;
351 }
352
353 /* Set/unset the full screen black flag */
354 /* Return nz on error */
madvrwin_set_fc(dispwin * p,int fullscreen)355 static int madvrwin_set_fc(dispwin *p, int fullscreen) {
356 int perc, bgperc, bgmode, border;
357
358 p->fullscreen = fullscreen;
359
360 /* Parameters that shouldn't change can be set to -1, but this doesn't seem */
361 /* to work for background level, so get current background level */
362 if (!madVR_GetPatternConfig(&perc, &bgperc, &bgmode, &border)) {
363 debugr2((errout,"madVR_GetPatternConfig failed\n"));
364 return 1;
365 }
366 debugr2((errout,"madvrwin_set_fc: got pattern config %i, %i, %i, %i\n",
367 perc, bgperc, bgmode, border));
368
369 /* Default test window is 10% of the width/height = 1% of the area*/
370 perc = (int)((p->width/100.0 * 0.1 * p->height/100.0 * 0.1) * 100.0 + 0.5);
371
372 /* Background level is 1..100 in percent */
373 debugr2((errout,"madvrwin_set_fc: setting pattern config %i, %i\n",
374 perc, fullscreen ? 0 : bgperc));
375 if (!madVR_SetPatternConfig(perc, fullscreen ? 0 : bgperc, -1, -1)) {
376 debugr2((errout,"madVR_SetPatternConfig failed\n"));
377 return 1;
378 }
379
380 return 0;
381 }
382
383 /* ----------------------------------------------- */
384 /* set patch info */
385 /* Return nz on error */
madvrwin_set_pinfo(dispwin * p,int pno,int tno)386 static int madvrwin_set_pinfo(dispwin *p, int pno, int tno) {
387
388 if (!madVR_SetProgressBarPos(pno, tno))
389 return 1;
390
391 return 0;
392 }
393
394 /* ----------------------------------------------- */
395 /* Set the shell set color callout */
madvrwin_set_callout(dispwin * p,char * callout)396 void madvrwin_set_callout(
397 dispwin *p,
398 char *callout
399 ) {
400 debugr2((errout,"madvrwin_set_callout called with '%s'\n",callout));
401
402 p->callout = strdup(callout);
403 }
404
405 /* ----------------------------------------------- */
406 /* Destroy ourselves */
madvrwin_del(dispwin * p)407 static void madvrwin_del(
408 dispwin *p
409 ) {
410
411 debugr("madvrwin_del called\n");
412
413 if (p == NULL)
414 return;
415
416 deinitMadVR(p);
417
418 if (p->name != NULL)
419 free(p->name);
420 if (p->description != NULL)
421 free(p->description);
422 if (p->callout != NULL)
423 free(p->callout);
424
425 /* Since we don't restore the display, delete these here */
426 if (p->oor != NULL) {
427 p->oor->del(p->oor);
428 p->oor = NULL;
429 }
430 if (p->or != NULL) {
431 p->or->del(p->or);
432 p->or = NULL;
433 }
434 if (p->r != NULL) {
435 p->r->del(p->r);
436 p->r = NULL;
437 }
438
439 free(p);
440 }
441
442 /* ----------------------------------------------- */
443
444 /* Create a web display test window, default grey */
new_madvrwin(double width,double height,double hoff,double voff,int nowin,int native,int * noramdac,int * nocm,int out_tvenc,int fullscreen,int verb,int ddebug)445 dispwin *new_madvrwin(
446 double width, double height, /* Width and height in mm - turned into % of screen */
447 double hoff, double voff, /* Offset from center in fraction of screen - ignored */
448 int nowin, /* NZ if no window should be created - RAMDAC access only */
449 int native, /* X0 = use current per channel calibration curve */
450 /* X1 = set native linear output and use ramdac high precn. */
451 /* 0X = use current color management cLut (MadVR) */
452 /* 1X = disable color management cLUT (MadVR) */
453 int *noramdac, /* Return nz if no ramdac access. native is set to X0 */
454 int *nocm, /* Return nz if no CM cLUT access. native is set to 0X */
455 int out_tvenc, /* 1 = use RGB Video Level encoding */
456 int fullscreen, /* NZ if whole screen should be filled with black */
457 int verb, /* NZ for verbose prompts */
458 int ddebug /* >0 to print debug statements to stderr */
459 ) {
460 dispwin *p = NULL;
461 char *cp;
462 const char *options[3];
463 char port[50];
464
465 debug("new_madvrwin called with native = %d\n");
466
467 if (out_tvenc) {
468 if (ddebug) fprintf(stderr,"new_madvrwin failed because out_tvenc set\n");
469 return NULL;
470 }
471
472 if ((p = (dispwin *)calloc(sizeof(dispwin), 1)) == NULL) {
473 if (ddebug) fprintf(stderr,"new_madvrwin failed because malloc failed\n");
474 return NULL;
475 }
476
477 /* !!!! Make changes in dispwin.c & webwin.c as well !!!! */
478 p->name = strdup("Web Window");
479 p->width = width;
480 p->height = height;
481 p->nowin = nowin;
482 p->native = native;
483 p->out_tvenc = 0;
484 p->fullscreen = fullscreen;
485 p->ddebug = ddebug;
486 p->get_ramdac = madvrwin_get_ramdac;
487 p->set_ramdac = madvrwin_set_ramdac;
488 p->install_profile = madvrwin_install_profile;
489 p->uninstall_profile = madvrwin_uninstall_profile;
490 p->get_profile = madvrwin_get_profile;
491 p->set_color = madvrwin_set_color;
492 p->set_fc = madvrwin_set_fc;
493 p->set_pinfo = madvrwin_set_pinfo;
494 p->set_update_delay = dispwin_set_update_delay;
495 p->set_settling_delay = dispwin_set_settling_delay;
496 p->enable_update_delay = dispwin_enable_update_delay;
497 p->set_callout = madvrwin_set_callout;
498 p->del = madvrwin_del;
499
500 debugr2((errout, "new_madvrwin got native = %d\n",native));
501
502 #ifndef ENABLE_RAMDAC
503 if (noramdac != NULL)
504 *noramdac = 1;
505 p->native &= ~1;
506 #endif
507
508 p->rgb[0] = p->rgb[1] = p->rgb[2] = 0.5; /* Set Grey as the initial test color */
509
510 dispwin_set_default_delays(p);
511
512 p->fdepth = 8; /* Assume this */
513 p->rdepth = p->fdepth; /* Assumed */
514 p->ndepth = p->rdepth; /* Assumed */
515 #ifdef ENABLE_RAMDAC
516 p->nent = (1 << p->ndepth);
517 #else
518 p->nent = 0; /* No ramdac */
519 #endif
520 p->edepth = 16; /* Assumed */
521
522 if (initMadVR(p)) {
523 debugr2((errout,"Failed to locate MadVR .dll or functions\n"));
524 free(p);
525 return NULL;
526 }
527
528 if (!madVR_BlindConnect(1, 1000)) {
529 debugr2((errout,"Failed to connect to MadVR\n"));
530 free(p);
531 return NULL;
532 }
533
534 if (p->native & 2) {
535 debugr2((errout,"new_madvrwin: disbling 3dLuts\n"));
536 madVR_Disable3dlut();
537 }
538
539 p->set_fc(p, fullscreen);
540
541 /* Create a suitable description */
542 {
543 char buf[1000];
544
545 sprintf(buf,"ArgyllCMS Patches");
546 p->description = strdup(buf);
547
548 if (verb)
549 printf("Created MadVR window\n");
550
551 madVR_SetOsdText(L"ArgyllCMS Patches");
552 }
553
554 #ifdef ENABLE_RAMDAC
555
556 /* Save the original ramdac, which gets restored on exit */
557 if ((p->or = p->get_ramdac(p)) != NULL) {
558
559 debugr("Saved original VideoLUT\n");
560
561 if (noramdac != NULL)
562 *noramdac = 0;
563
564 /* Copy original ramdac that never gets altered */
565 if ((p->oor = p->or->clone(p->or)) == NULL) {
566 madvrwin_del(p);
567 debugr("ramdac clone failed - memory ?\n");
568 return NULL;
569 }
570
571 /* Create a working ramdac for native or other use */
572 if ((p->r = p->or->clone(p->or)) == NULL) {
573 madvrwin_del(p);
574 debugr("ramdac clone failed - memory ?\n");
575 return NULL;
576 }
577
578 /* Setup for native mode == linear RAMDAC */
579 if ((p->native & 1) == 1) {
580 int ii = 0;
581 debug("About to setup native mode\n");
582
583 /* Since we MadVR does dithering, we don't need to use the VideoLUTs */
584 /* to emulate higher precision, so simply set it to linear here. */
585 if ((ii = madVR_SetDeviceGammaRamp(NULL)) == 0) {
586 madvrwin_del(p);
587 debugr("Clear gamma ramp failed\n");
588 return NULL;
589 }
590 }
591
592 } else {
593 debugr2((errout,"Unable to access VideoLUT\n"));
594 if (noramdac != NULL)
595 *noramdac = 1;
596 p->oor = p->or = p->r = NULL;
597 }
598
599 if (!p->nowin) {
600
601 /* Make sure initial test color is displayed */
602 madvrwin_set_color(p, p->rgb[0], p->rgb[1], p->rgb[2]);
603 }
604 #endif
605
606 debugr("new_madvrwin: return sucessfully\n");
607
608 return p;
609 }
610
611