1 /*
2 * Copyright © 2007 Novell, Inc.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software
5 * and its documentation for any purpose is hereby granted without
6 * fee, provided that the above copyright notice appear in all copies
7 * and that both that copyright notice and this permission notice
8 * appear in supporting documentation, and that the name of
9 * Novell, Inc. not be used in advertising or publicity pertaining to
10 * distribution of the software without specific, written prior permission.
11 * Novell, Inc. makes no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
13 * implied warranty.
14 *
15 * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17 * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Author: David Reveman <davidr@novell.com>
24 */
25
26 #include <compiz-core.h>
27
28 #include <string.h>
29 #include <stdlib.h>
30
31 #define COMP_FUNCTION_TYPE_ARB 0
32 #define COMP_FUNCTION_TYPE_NUM 1
33
34 #define COMP_FUNCTION_ARB_MASK (1 << 0)
35 #define COMP_FUNCTION_MASK (COMP_FUNCTION_ARB_MASK)
36
37 struct _CompProgram {
38 struct _CompProgram *next;
39
40 int *signature;
41 int nSignature;
42
43 Bool blending;
44
45 GLuint name;
46 GLenum type;
47 };
48
49 typedef enum {
50 CompOpTypeData,
51 CompOpTypeDataStore,
52 CompOpTypeDataOffset,
53 CompOpTypeDataBlend,
54 CompOpTypeHeaderTemp,
55 CompOpTypeHeaderParam,
56 CompOpTypeHeaderAttrib,
57 CompOpTypeColor,
58 CompOpTypeFetch,
59 CompOpTypeLoad
60 } CompOpType;
61
62 typedef struct _CompDataOp {
63 CompOpType type;
64
65 char *data;
66 } CompDataOp;
67
68 typedef struct _CompHeaderOp {
69 CompOpType type;
70
71 char *name;
72 } CompHeaderOp;
73
74 typedef struct _CompFetchOp {
75 CompOpType type;
76
77 char *dst;
78 char *offset;
79 int target;
80 } CompFetchOp;
81
82 typedef struct _CompLoadOp {
83 CompOpType type;
84
85 char *noOffset[COMP_FETCH_TARGET_NUM];
86 char *offset[COMP_FETCH_TARGET_NUM];
87 } CompLoadOp;
88
89 typedef struct _CompColorOp {
90 CompOpType type;
91
92 char *dst;
93 char *src;
94 } CompColorOp;
95
96 typedef union _CompBodyOp {
97 CompOpType type;
98
99 CompDataOp data;
100 CompFetchOp fetch;
101 CompLoadOp load;
102 CompColorOp color;
103 } CompBodyOp;
104
105 struct _CompFunctionData {
106 CompHeaderOp *header;
107 int nHeader;
108
109 CompBodyOp *body;
110 int nBody;
111 };
112
113 struct _CompFunction {
114 struct _CompFunction *next;
115
116 int id;
117 char *name;
118 CompFunctionData data[COMP_FUNCTION_TYPE_NUM];
119 int mask;
120 };
121
122 typedef struct _FetchInfo {
123 int indices[MAX_FRAGMENT_FUNCTIONS];
124 char *data;
125 } FetchInfo;
126
127 typedef void (*DataOpCallBackProc) (CompDataOp *op,
128 int index,
129 void *closure);
130
131 static CompLoadOp loadArbFpData = {
132 CompOpTypeLoad,
133 {
134 "TEX output, fragment.texcoord[0], texture[0], 2D;",
135 "TEX output, fragment.texcoord[0], texture[0], RECT;"
136 }, {
137 "TEX output, __tmp_texcoord0, texture[0], 2D;",
138 "TEX output, __tmp_texcoord0, texture[0], RECT;"
139 }
140 };
141
142 static CompFunction initialLoadFunction = {
143 NULL,
144 0,
145 "__core_load",
146 {
147 {
148 NULL,
149 0,
150 (CompBodyOp *) &loadArbFpData,
151 1
152 }
153 },
154 COMP_FUNCTION_MASK
155 };
156
157 static CompFunction *
findFragmentFunction(CompScreen * s,int id)158 findFragmentFunction (CompScreen *s,
159 int id)
160 {
161 CompFunction *function;
162
163 for (function = s->fragmentFunctions; function; function = function->next)
164 {
165 if (function->id == id)
166 return function;
167 }
168
169 return NULL;
170 }
171
172 static CompFunction *
findFragmentFunctionWithName(CompScreen * s,const char * name)173 findFragmentFunctionWithName (CompScreen *s,
174 const char *name)
175 {
176 CompFunction *function;
177
178 for (function = s->fragmentFunctions; function; function = function->next)
179 {
180 if (strcmp (function->name, name) == 0)
181 return function;
182 }
183
184 return NULL;
185 }
186
187 static CompProgram *
findFragmentProgram(CompScreen * s,int * signature,int nSignature)188 findFragmentProgram (CompScreen *s,
189 int *signature,
190 int nSignature)
191 {
192 CompProgram *program;
193 int i;
194
195 for (program = s->fragmentPrograms; program; program = program->next)
196 {
197 if (nSignature != program->nSignature)
198 continue;
199
200 for (i = 0; i < nSignature; i++)
201 {
202 if (program->signature[i] != signature[i])
203 break;
204 }
205
206 if (i == nSignature)
207 return program;
208 }
209
210 return NULL;
211 }
212
213 static int
functionMaskToType(int mask)214 functionMaskToType (int mask)
215 {
216 static struct {
217 int type;
218 int mask;
219 } maskToType[] = {
220 { COMP_FUNCTION_TYPE_ARB, COMP_FUNCTION_ARB_MASK }
221 };
222 int i;
223
224 for (i = 0; i < sizeof (maskToType) / sizeof (maskToType[0]); i++)
225 if (mask & maskToType[i].mask)
226 return maskToType[i].type;
227
228 return 0;
229 }
230
231 static void
forEachDataOpInFunction(CompFunction ** list,int index,int type,int loadTarget,char * loadOffset,Bool * color,Bool * blend,DataOpCallBackProc callBack,void * closure)232 forEachDataOpInFunction (CompFunction **list,
233 int index,
234 int type,
235 int loadTarget,
236 char *loadOffset,
237 Bool *color,
238 Bool *blend,
239 DataOpCallBackProc callBack,
240 void *closure)
241 {
242 CompFunction *f = list[index];
243 CompDataOp dataOp;
244 char data[256];
245 Bool colorDone = FALSE;
246 Bool blendDone = FALSE;
247 int i;
248
249 *color = FALSE;
250 *blend = FALSE;
251
252 for (i = 0; i < f->data[type].nBody; i++)
253 {
254 switch (f->data[type].body[i].type) {
255 case CompOpTypeFetch: {
256 char *offset = loadOffset;
257
258 /* add offset */
259 if (f->data[type].body[i].fetch.offset)
260 {
261 if (loadOffset)
262 {
263 snprintf (data, 256,
264 "ADD __tmp_texcoord%d, %s, %s;",
265 index, loadOffset,
266 f->data[type].body[i].fetch.offset);
267
268 dataOp.type = CompOpTypeDataOffset;
269 dataOp.data = data;
270
271 (*callBack) (&dataOp, index, closure);
272
273 snprintf (data, 256, "__tmp_texcoord%d", index);
274
275 offset = data;
276 }
277 else
278 {
279 offset = f->data[type].body[i].fetch.offset;
280 }
281 }
282
283 forEachDataOpInFunction (list, index - 1, type,
284 f->data[type].body[i].fetch.target,
285 offset, &colorDone, &blendDone,
286 callBack, closure);
287
288 if (strcmp (f->data[type].body[i].fetch.dst, "output"))
289 {
290 snprintf (data, 256,
291 "MOV %s, output;",
292 f->data[type].body[i].fetch.dst);
293
294 dataOp.type = CompOpTypeDataStore;
295 dataOp.data = data;
296
297 /* move to destination */
298 (*callBack) (&dataOp, index, closure);
299 }
300 } break;
301 case CompOpTypeLoad:
302 if (loadOffset)
303 {
304 snprintf (data, 256,
305 "ADD __tmp_texcoord0, fragment.texcoord[0], %s;",
306 loadOffset);
307
308 dataOp.type = CompOpTypeDataOffset;
309 dataOp.data = data;
310
311 (*callBack) (&dataOp, index, closure);
312
313 dataOp.data = f->data[type].body[i].load.offset[loadTarget];
314 }
315 else
316 {
317 dataOp.data = f->data[type].body[i].load.noOffset[loadTarget];
318 }
319
320 dataOp.type = CompOpTypeData;
321
322 (*callBack) (&dataOp, index, closure);
323
324 break;
325 case CompOpTypeColor:
326 if (!colorDone)
327 {
328 snprintf (data, 256,
329 "MUL %s, fragment.color, %s;",
330 f->data[type].body[i].color.dst,
331 f->data[type].body[i].color.src);
332
333 dataOp.type = CompOpTypeData;
334 dataOp.data = data;
335
336 (*callBack) (&dataOp, index, closure);
337 }
338 else if (strcmp (f->data[type].body[i].color.dst,
339 f->data[type].body[i].color.src))
340 {
341 snprintf (data, 256,
342 "MOV %s, %s;",
343 f->data[type].body[i].color.dst,
344 f->data[type].body[i].color.src);
345
346 dataOp.type = CompOpTypeData;
347 dataOp.data = data;
348
349 (*callBack) (&dataOp, index, closure);
350 }
351 *color = TRUE;
352 break;
353 case CompOpTypeDataBlend:
354 *blend = TRUE;
355 /* fall-through */
356 case CompOpTypeData:
357 (*callBack) (&f->data[type].body[i].data, index, closure);
358 break;
359 case CompOpTypeDataStore:
360 case CompOpTypeDataOffset:
361 case CompOpTypeHeaderTemp:
362 case CompOpTypeHeaderParam:
363 case CompOpTypeHeaderAttrib:
364 break;
365 }
366 }
367
368 if (colorDone)
369 *color = TRUE;
370
371 if (blendDone)
372 *blend = TRUE;
373 }
374
375 static int
forEachHeaderOpWithType(CompHeaderOp * header,int nHeader,int index,CompOpType type,char * prefix,char * functionPrefix,int count,DataOpCallBackProc callBack,void * closure)376 forEachHeaderOpWithType (CompHeaderOp *header,
377 int nHeader,
378 int index,
379 CompOpType type,
380 char *prefix,
381 char *functionPrefix,
382 int count,
383 DataOpCallBackProc callBack,
384 void *closure)
385 {
386 CompDataOp dataOp;
387 int i;
388
389 dataOp.type = CompOpTypeData;
390
391 for (i = 0; i < nHeader; i++)
392 {
393 if (header[i].type == type)
394 {
395 if (count)
396 {
397 dataOp.data = ", ";
398 (*callBack) (&dataOp, index, closure);
399 }
400 else
401 {
402 dataOp.data = prefix;
403 (*callBack) (&dataOp, index, closure);
404 }
405
406 dataOp.data = functionPrefix;
407 (*callBack) (&dataOp, index, closure);
408
409 dataOp.data = "_";
410 (*callBack) (&dataOp, index, closure);
411
412 dataOp.data = header[i].name;
413 (*callBack) (&dataOp, index, closure);
414
415 count++;
416 }
417 }
418
419 return count;
420 }
421
422 static Bool
forEachDataOp(CompFunction ** list,int nList,int type,DataOpCallBackProc callBack,void * closure)423 forEachDataOp (CompFunction **list,
424 int nList,
425 int type,
426 DataOpCallBackProc callBack,
427 void *closure)
428 {
429 CompDataOp dataOp;
430 Bool colorDone;
431 Bool blendDone;
432 int i, count;
433
434 dataOp.type = CompOpTypeData;
435
436 count = 1;
437
438 dataOp.data = "TEMP output";
439
440 (*callBack) (&dataOp, nList, closure);
441
442 for (i = 0; i < nList; i++)
443 count = forEachHeaderOpWithType (list[i]->data[type].header,
444 list[i]->data[type].nHeader,
445 nList, CompOpTypeHeaderTemp,
446 NULL, list[i]->name, count,
447 callBack, closure);
448
449 dataOp.data = ";";
450
451 (*callBack) (&dataOp, nList, closure);
452
453 count = 0;
454
455 for (i = 0; i < nList; i++)
456 count = forEachHeaderOpWithType (list[i]->data[type].header,
457 list[i]->data[type].nHeader,
458 nList, CompOpTypeHeaderParam,
459 "PARAM ", list[i]->name, count,
460 callBack, closure);
461
462 if (count)
463 {
464 dataOp.data = ";";
465
466 (*callBack) (&dataOp, nList, closure);
467 }
468
469 count = 0;
470
471 for (i = 0; i < nList; i++)
472 count = forEachHeaderOpWithType (list[i]->data[type].header,
473 list[i]->data[type].nHeader,
474 nList, CompOpTypeHeaderAttrib,
475 "ATTRIB ", list[i]->name, count,
476 callBack, closure);
477
478 if (count)
479 {
480 dataOp.data = ";";
481
482 (*callBack) (&dataOp, nList, closure);
483 }
484
485 forEachDataOpInFunction (list, nList - 1, type, 0, NULL,
486 &colorDone, &blendDone,
487 callBack, closure);
488
489 if (colorDone)
490 dataOp.data = "MOV result.color, output;END";
491 else
492 dataOp.data = "MUL result.color, fragment.color, output;END";
493
494 (*callBack) (&dataOp, nList, closure);
495
496 return blendDone;
497 }
498
499 static void
addFetchOffsetVariables(CompDataOp * op,int index,void * closure)500 addFetchOffsetVariables (CompDataOp *op,
501 int index,
502 void *closure)
503 {
504 if (op->type == CompOpTypeDataOffset)
505 {
506 FetchInfo *info = (FetchInfo *) closure;
507
508 if (!info->indices[index])
509 {
510 char *str;
511 int oldSize = strlen (info->data);
512 int newSize;
513 char data[256];
514
515 snprintf (data, 256, "TEMP __tmp_texcoord%d;", index);
516
517 newSize = oldSize + strlen (data);
518
519 str = realloc (info->data, newSize + 1);
520 if (str)
521 {
522 strcpy (str + oldSize, data);
523 info->data = str;
524 }
525
526 info->indices[index] = TRUE;
527 }
528 }
529 }
530
531 static void
addData(CompDataOp * op,int index,void * closure)532 addData (CompDataOp *op,
533 int index,
534 void *closure)
535 {
536 FetchInfo *info = (FetchInfo *) closure;
537 char *str;
538 int oldSize = strlen (info->data);
539 int newSize = oldSize + strlen (op->data);
540
541 str = realloc (info->data, newSize + 1);
542 if (str)
543 {
544 strcpy (str + oldSize, op->data);
545 info->data = str;
546 }
547 }
548
549 static CompProgram *
buildFragmentProgram(CompScreen * s,FragmentAttrib * attrib)550 buildFragmentProgram (CompScreen *s,
551 FragmentAttrib *attrib)
552 {
553 CompProgram *program;
554 CompFunction **functionList;
555 int nFunctionList;
556 int mask = COMP_FUNCTION_MASK;
557 int type;
558 GLint errorPos;
559 FetchInfo info;
560 int i;
561
562 program = malloc (sizeof (CompProgram));
563 if (!program)
564 return NULL;
565
566 functionList = malloc ((attrib->nFunction + 1) * sizeof (void *));
567 if (!functionList)
568 {
569 free (program);
570
571 return NULL;
572 }
573
574 functionList[0] = &initialLoadFunction;
575 nFunctionList = 1;
576
577 for (i = 0; i < attrib->nFunction; i++)
578 {
579 functionList[nFunctionList] =
580 findFragmentFunction (s, attrib->function[i]);
581 if (functionList[nFunctionList])
582 nFunctionList++;
583 }
584
585 for (i = 0; i < nFunctionList; i++)
586 mask &= functionList[i]->mask;
587
588 if (!mask)
589 {
590 compLogMessage ("core", CompLogLevelWarn,
591 "fragment functions can't be linked together "
592 "because a common type doesn't exist");
593 }
594
595 if (!mask || nFunctionList == 1)
596 {
597 free (program);
598 free (functionList);
599
600 return NULL;
601 }
602
603 program->signature = malloc (attrib->nFunction * sizeof (int));
604 if (!program->signature)
605 {
606 free (program);
607 free (functionList);
608
609 return NULL;
610 }
611
612 for (i = 0; i < attrib->nFunction; i++)
613 program->signature[i] = attrib->function[i];
614
615 program->nSignature = attrib->nFunction;
616
617 type = functionMaskToType (mask);
618
619 info.data = strdup ("!!ARBfp1.0");
620
621 memset (info.indices, 0, sizeof (info.indices));
622
623 forEachDataOp (functionList, nFunctionList, type,
624 addFetchOffsetVariables, (void *) &info);
625
626 program->blending = forEachDataOp (functionList, nFunctionList, type,
627 addData, (void *) &info);
628
629 program->type = GL_FRAGMENT_PROGRAM_ARB;
630
631 glGetError ();
632
633 (*s->genPrograms) (1, &program->name);
634 (*s->bindProgram) (GL_FRAGMENT_PROGRAM_ARB, program->name);
635 (*s->programString) (GL_FRAGMENT_PROGRAM_ARB,
636 GL_PROGRAM_FORMAT_ASCII_ARB,
637 strlen (info.data), info.data);
638
639 glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
640 if (glGetError () != GL_NO_ERROR || errorPos != -1)
641 {
642 compLogMessage ("core", CompLogLevelError,
643 "failed to load fragment program");
644
645 (*s->deletePrograms) (1, &program->name);
646
647 program->name = 0;
648 program->type = 0;
649 }
650
651 free (info.data);
652 free (functionList);
653
654 return program;
655 }
656
657 static GLuint
getFragmentProgram(CompScreen * s,FragmentAttrib * attrib,GLenum * type,Bool * blending)658 getFragmentProgram (CompScreen *s,
659 FragmentAttrib *attrib,
660 GLenum *type,
661 Bool *blending)
662 {
663 CompProgram *program;
664
665 if (!attrib->nFunction)
666 return 0;
667
668 program = findFragmentProgram (s, attrib->function, attrib->nFunction);
669 if (!program)
670 {
671 program = buildFragmentProgram (s, attrib);
672 if (program)
673 {
674 program->next = s->fragmentPrograms;
675 s->fragmentPrograms = program;
676 }
677 }
678
679 if (program)
680 {
681 *type = program->type;
682 *blending = program->blending;
683
684 return program->name;
685 }
686
687 return 0;
688 }
689
690 CompFunctionData *
createFunctionData(void)691 createFunctionData (void)
692 {
693 CompFunctionData *data;
694
695 data = malloc (sizeof (CompFunctionData));
696 if (!data)
697 return NULL;
698
699 data->header = NULL;
700 data->nHeader = 0;
701
702 data->body = NULL;
703 data->nBody = 0;
704
705 return data;
706 }
707
708 static void
finiFunctionData(CompFunctionData * data)709 finiFunctionData (CompFunctionData *data)
710 {
711 int i;
712
713 for (i = 0; i < data->nHeader; i++)
714 free (data->header[i].name);
715
716 if (data->header)
717 free (data->header);
718
719 for (i = 0; i < data->nBody; i++)
720 {
721 switch (data->body[i].type) {
722 case CompOpTypeFetch:
723 free (data->body[i].fetch.dst);
724 if (data->body[i].fetch.offset)
725 free (data->body[i].fetch.offset);
726 break;
727 case CompOpTypeLoad:
728 case CompOpTypeHeaderTemp:
729 case CompOpTypeHeaderParam:
730 case CompOpTypeHeaderAttrib:
731 break;
732 case CompOpTypeData:
733 case CompOpTypeDataBlend:
734 case CompOpTypeDataStore:
735 case CompOpTypeDataOffset:
736 free (data->body[i].data.data);
737 break;
738 case CompOpTypeColor:
739 free (data->body[i].color.dst);
740 free (data->body[i].color.src);
741 break;
742 }
743 }
744
745 if (data->body)
746 free (data->body);
747 }
748
749 void
destroyFunctionData(CompFunctionData * data)750 destroyFunctionData (CompFunctionData *data)
751 {
752 finiFunctionData (data);
753 free (data);
754 }
755
756 /* performs simple variable substitution */
757 static char *
copyData(CompHeaderOp * header,int nHeader,const char * prefix,char * data)758 copyData (CompHeaderOp *header,
759 int nHeader,
760 const char *prefix,
761 char *data)
762 {
763 char *copy, *needle, *haystack, *dst, *first;
764 int i, index, length, prefixLength, count = 0;
765
766 prefixLength = strlen (prefix);
767
768 for (i = 0; i < nHeader; i++)
769 {
770 length = strlen (header[i].name);
771 haystack = data;
772
773 do {
774 needle = strstr (haystack, header[i].name);
775 if (needle)
776 {
777 haystack = needle + length;
778 count++;
779 }
780 } while (needle);
781 }
782
783 /* allocate new memory that will fit all substitutions */
784 copy = malloc (strlen (data) + count * (strlen (prefix) + 1) + 1);
785 if (!copy)
786 return NULL;
787
788 haystack = data;
789 dst = copy;
790
791 for (;;)
792 {
793 first = NULL;
794 index = 0;
795
796 for (i = 0; i < nHeader; i++)
797 {
798 needle = strstr (haystack, header[i].name);
799 if (needle && (!first || needle < first))
800 {
801 first = needle;
802 index = i;
803 }
804 }
805
806 if (first)
807 {
808 int length;
809
810 if (first > haystack)
811 {
812 strncpy (dst, haystack, first - haystack);
813 dst += first - haystack;
814 }
815
816 length = strlen (header[index].name);
817
818 strcpy (dst, prefix);
819 dst += prefixLength;
820 *dst++ = '_';
821 strcpy (dst, header[index].name);
822 dst += length;
823
824 haystack = first + length;
825 }
826 else
827 {
828 strcpy (dst, haystack);
829 break;
830 }
831 }
832
833 return copy;
834 }
835
836 static Bool
copyFunctionData(CompFunctionData * dst,const CompFunctionData * src,const char * dstPrefix)837 copyFunctionData (CompFunctionData *dst,
838 const CompFunctionData *src,
839 const char *dstPrefix)
840 {
841 int i;
842
843 dst->header = malloc (src->nHeader * sizeof (CompHeaderOp));
844 if (!dst->header)
845 return FALSE;
846
847 dst->body = malloc (src->nBody * sizeof (CompBodyOp));
848 if (!dst->body)
849 {
850 free (dst->header);
851 return FALSE;
852 }
853
854 dst->nHeader = src->nHeader;
855
856 for (i = 0; i < src->nHeader; i++)
857 {
858 dst->header[i].type = src->header[i].type;
859 dst->header[i].name = strdup (src->header[i].name);
860 }
861
862 dst->nBody = src->nBody;
863
864 for (i = 0; i < src->nBody; i++)
865 {
866 dst->body[i].type = src->body[i].type;
867
868 switch (src->body[i].type) {
869 case CompOpTypeFetch:
870 dst->body[i].fetch.dst = copyData (dst->header,
871 dst->nHeader,
872 dstPrefix,
873 src->body[i].fetch.dst);
874 if (src->body[i].fetch.offset)
875 dst->body[i].fetch.offset =
876 copyData (dst->header,
877 dst->nHeader,
878 dstPrefix,
879 src->body[i].fetch.offset);
880 else
881 dst->body[i].fetch.offset = NULL;
882
883 dst->body[i].fetch.target = src->body[i].fetch.target;
884 break;
885 case CompOpTypeLoad:
886 case CompOpTypeHeaderTemp:
887 case CompOpTypeHeaderParam:
888 case CompOpTypeHeaderAttrib:
889 break;
890 case CompOpTypeData:
891 case CompOpTypeDataBlend:
892 case CompOpTypeDataStore:
893 case CompOpTypeDataOffset:
894 dst->body[i].data.data = copyData (dst->header,
895 dst->nHeader,
896 dstPrefix,
897 src->body[i].data.data);
898 break;
899 case CompOpTypeColor:
900 dst->body[i].color.dst = copyData (dst->header,
901 dst->nHeader,
902 dstPrefix,
903 src->body[i].color.dst);
904 dst->body[i].color.src = copyData (dst->header,
905 dst->nHeader,
906 dstPrefix,
907 src->body[i].color.src);
908 break;
909 }
910 }
911
912 return TRUE;
913 }
914
915 static Bool
addHeaderOpToFunctionData(CompFunctionData * data,const char * name,CompOpType type)916 addHeaderOpToFunctionData (CompFunctionData *data,
917 const char *name,
918 CompOpType type)
919 {
920 static char *reserved[] = {
921 "output",
922 "__tmp_texcoord",
923 "fragment",
924 "program",
925 "result",
926 "state",
927 "texture"
928 };
929 CompHeaderOp *header;
930 int i;
931
932 for (i = 0; i < sizeof (reserved) / sizeof (reserved[0]); i++)
933 {
934 if (strncmp (name, reserved[i], strlen (reserved[i])) == 0)
935 {
936 compLogMessage ("core", CompLogLevelWarn,
937 "%s is a reserved word", name);
938 return FALSE;
939 }
940 }
941
942 header = realloc (data->header,
943 (data->nHeader + 1) * sizeof (CompHeaderOp));
944 if (!header)
945 return FALSE;
946
947 header[data->nHeader].type = type;
948 header[data->nHeader].name = strdup (name);
949
950 data->header = header;
951 data->nHeader++;
952
953 return TRUE;
954 }
955
956 Bool
addTempHeaderOpToFunctionData(CompFunctionData * data,const char * name)957 addTempHeaderOpToFunctionData (CompFunctionData *data,
958 const char *name)
959 {
960 return addHeaderOpToFunctionData (data, name, CompOpTypeHeaderTemp);
961 }
962
963 Bool
addParamHeaderOpToFunctionData(CompFunctionData * data,const char * name)964 addParamHeaderOpToFunctionData (CompFunctionData *data,
965 const char *name)
966 {
967 return addHeaderOpToFunctionData (data, name, CompOpTypeHeaderParam);
968 }
969
970 Bool
addAttribHeaderOpToFunctionData(CompFunctionData * data,const char * name)971 addAttribHeaderOpToFunctionData (CompFunctionData *data,
972 const char *name)
973 {
974 return addHeaderOpToFunctionData (data, name, CompOpTypeHeaderAttrib);
975 }
976
977 static Bool
allocBodyOpInFunctionData(CompFunctionData * data)978 allocBodyOpInFunctionData (CompFunctionData *data)
979 {
980 CompBodyOp *body;
981
982 body = realloc (data->body, (data->nBody + 1) * sizeof (CompBodyOp));
983 if (!body)
984 return FALSE;
985
986 data->body = body;
987 data->nBody++;
988
989 return TRUE;
990 }
991
992 Bool
addFetchOpToFunctionData(CompFunctionData * data,const char * dst,const char * offset,int target)993 addFetchOpToFunctionData (CompFunctionData *data,
994 const char *dst,
995 const char *offset,
996 int target)
997 {
998 int index = data->nBody;
999
1000 if (!allocBodyOpInFunctionData (data))
1001 return FALSE;
1002
1003 data->body[index].type = CompOpTypeFetch;
1004 data->body[index].fetch.dst = strdup (dst);
1005 data->body[index].fetch.target = target;
1006
1007 if (offset)
1008 data->body[index].fetch.offset = strdup (offset);
1009 else
1010 data->body[index].fetch.offset = NULL;
1011
1012 return TRUE;
1013 }
1014
1015 Bool
addColorOpToFunctionData(CompFunctionData * data,const char * dst,const char * src)1016 addColorOpToFunctionData (CompFunctionData *data,
1017 const char *dst,
1018 const char *src)
1019 {
1020 int index = data->nBody;
1021
1022 if (!allocBodyOpInFunctionData (data))
1023 return FALSE;
1024
1025 data->body[index].type = CompOpTypeColor;
1026 data->body[index].color.dst = strdup (dst);
1027 data->body[index].color.src = strdup (src);
1028
1029 return TRUE;
1030 }
1031
1032 Bool
addDataOpToFunctionData(CompFunctionData * data,const char * str,...)1033 addDataOpToFunctionData (CompFunctionData *data,
1034 const char *str,
1035 ...)
1036 {
1037 int index = data->nBody;
1038 int size = strlen (str) + 1;
1039 int n;
1040 char *fStr;
1041 char *tmp;
1042 va_list ap;
1043
1044 if (!allocBodyOpInFunctionData (data))
1045 return FALSE;
1046
1047 fStr = malloc (size);
1048 if (!fStr)
1049 return FALSE;
1050
1051 while (1)
1052 {
1053 /* Try to print in the allocated space. */
1054 va_start (ap, str);
1055 n = vsnprintf (fStr, size, str, ap);
1056 va_end (ap);
1057
1058 /* If that worked, leave the loop. */
1059 if (n > -1 && n < size)
1060 break;
1061
1062 /* Else try again with more space. */
1063 if (n > -1) /* glibc 2.1 */
1064 size = n + 1; /* precisely what is needed */
1065 else /* glibc 2.0 */
1066 size++; /* one more than the old size */
1067
1068 tmp = realloc (fStr, size);
1069 if (!tmp)
1070 {
1071 free (fStr);
1072 return FALSE;
1073 }
1074 else
1075 {
1076 fStr = tmp;
1077 }
1078 }
1079
1080 data->body[index].type = CompOpTypeData;
1081 data->body[index].data.data = fStr;
1082
1083 return TRUE;
1084 }
1085
1086 Bool
addBlendOpToFunctionData(CompFunctionData * data,const char * str,...)1087 addBlendOpToFunctionData (CompFunctionData *data,
1088 const char *str,
1089 ...)
1090 {
1091 int index = data->nBody;
1092 int size = strlen (str) + 1;
1093 int n;
1094 char *fStr;
1095 char *tmp;
1096 va_list ap;
1097
1098 if (!allocBodyOpInFunctionData (data))
1099 return FALSE;
1100
1101 fStr = malloc (size);
1102 if (!fStr)
1103 return FALSE;
1104
1105 while (1)
1106 {
1107 /* Try to print in the allocated space. */
1108 va_start (ap, str);
1109 n = vsnprintf (fStr, size, str, ap);
1110 va_end (ap);
1111
1112 /* If that worked, leave the loop. */
1113 if (n > -1 && n < size)
1114 break;
1115
1116 /* Else try again with more space. */
1117 if (n > -1) /* glibc 2.1 */
1118 size = n + 1; /* precisely what is needed */
1119 else /* glibc 2.0 */
1120 size++; /* one more than the old size */
1121
1122 tmp = realloc (fStr, size);
1123 if (!tmp)
1124 {
1125 free (fStr);
1126 return FALSE;
1127 }
1128 else
1129 {
1130 fStr = tmp;
1131 }
1132 }
1133
1134 data->body[index].type = CompOpTypeDataBlend;
1135 data->body[index].data.data = fStr;
1136
1137 return TRUE;
1138 }
1139
1140 static int
allocFunctionId(CompScreen * s)1141 allocFunctionId (CompScreen *s)
1142 {
1143 return ++s->lastFunctionId;
1144 }
1145
1146 int
createFragmentFunction(CompScreen * s,const char * name,CompFunctionData * data)1147 createFragmentFunction (CompScreen *s,
1148 const char *name,
1149 CompFunctionData *data)
1150 {
1151 CompFunction *function;
1152 const char *validName = name;
1153 char *nameBuffer = NULL;
1154 int i = 0;
1155
1156 while (findFragmentFunctionWithName (s, validName))
1157 {
1158 if (!nameBuffer)
1159 {
1160 nameBuffer = malloc (strlen (name) + 64);
1161 if (!nameBuffer)
1162 return 0;
1163
1164 validName = nameBuffer;
1165 }
1166
1167 sprintf (nameBuffer, "%s%d", name, i++);
1168 }
1169
1170 function = malloc (sizeof (CompFunction));
1171 if (!function)
1172 {
1173 if (nameBuffer)
1174 free (nameBuffer);
1175
1176 return 0;
1177 }
1178
1179 if (!copyFunctionData (&function->data[COMP_FUNCTION_TYPE_ARB], data,
1180 validName))
1181 {
1182 free (function);
1183 if (nameBuffer)
1184 free (nameBuffer);
1185
1186 return 0;
1187 }
1188
1189 function->name = strdup (validName);
1190 function->mask = COMP_FUNCTION_ARB_MASK;
1191 function->id = allocFunctionId (s);
1192
1193 function->next = s->fragmentFunctions;
1194 s->fragmentFunctions = function;
1195
1196 if (nameBuffer)
1197 free (nameBuffer);
1198
1199 return function->id;
1200 }
1201
1202 void
destroyFragmentFunction(CompScreen * s,int id)1203 destroyFragmentFunction (CompScreen *s,
1204 int id)
1205 {
1206 CompFunction *function, *prevFunction = NULL;
1207 CompProgram *program, *prevProgram = NULL;
1208 int i;
1209
1210 for (function = s->fragmentFunctions; function; function = function->next)
1211 {
1212 if (function->id == id)
1213 break;
1214
1215 prevFunction = function;
1216 }
1217
1218 if (!function)
1219 return;
1220
1221 program = s->fragmentPrograms;
1222 while (program)
1223 {
1224 for (i = 0; i < program->nSignature; i++)
1225 {
1226 if (program->signature[i] == id)
1227 break;
1228 }
1229
1230 if (i < program->nSignature)
1231 {
1232 CompProgram *tmp = program;
1233
1234 if (prevProgram)
1235 prevProgram->next = program->next;
1236 else
1237 s->fragmentPrograms = program->next;
1238
1239 program = program->next;
1240
1241 (*s->deletePrograms) (1, &tmp->name);
1242
1243 free (tmp->signature);
1244 free (tmp);
1245 }
1246 else
1247 {
1248 prevProgram = program;
1249 program = program->next;
1250 }
1251 }
1252
1253 if (prevFunction)
1254 prevFunction->next = function->next;
1255 else
1256 s->fragmentFunctions = function->next;
1257
1258 finiFunctionData (&function->data[COMP_FUNCTION_TYPE_ARB]);
1259 free (function->name);
1260 free (function);
1261 }
1262
1263 int
getSaturateFragmentFunction(CompScreen * s,CompTexture * texture,int param)1264 getSaturateFragmentFunction (CompScreen *s,
1265 CompTexture *texture,
1266 int param)
1267 {
1268 int target;
1269
1270 if (param >= 64)
1271 return 0;
1272
1273 if (texture->target == GL_TEXTURE_2D)
1274 target = COMP_FETCH_TARGET_2D;
1275 else
1276 target = COMP_FETCH_TARGET_RECT;
1277
1278 if (!s->saturateFunction[target][param])
1279 {
1280 static const char *saturateData =
1281 "MUL temp, output, { 1.0, 1.0, 1.0, 0.0 };"
1282 "DP3 temp, temp, program.env[%d];"
1283 "LRP output.xyz, program.env[%d].w, output, temp;";
1284 CompFunctionData *data;
1285
1286 data = createFunctionData ();
1287 if (data)
1288 {
1289 char str[1024];
1290
1291 if (!addTempHeaderOpToFunctionData (data, "temp"))
1292 {
1293 destroyFunctionData (data);
1294 return 0;
1295 }
1296
1297 if (!addFetchOpToFunctionData (data, "output", NULL, target))
1298 {
1299 destroyFunctionData (data);
1300 return 0;
1301 }
1302
1303 if (!addColorOpToFunctionData (data, "output", "output"))
1304 {
1305 destroyFunctionData (data);
1306 return 0;
1307 }
1308
1309 snprintf (str, 1024, saturateData, param, param);
1310
1311 if (!addDataOpToFunctionData (data, str))
1312 {
1313 destroyFunctionData (data);
1314 return 0;
1315 }
1316
1317 s->saturateFunction[target][param] =
1318 createFragmentFunction (s, "__core_saturate", data);
1319
1320 destroyFunctionData (data);
1321 }
1322 }
1323
1324 return s->saturateFunction[target][param];
1325 }
1326
1327 int
allocFragmentTextureUnits(FragmentAttrib * attrib,int nTexture)1328 allocFragmentTextureUnits (FragmentAttrib *attrib,
1329 int nTexture)
1330 {
1331 int first = attrib->nTexture;
1332
1333 attrib->nTexture += nTexture;
1334
1335 /* 0 is reserved for source texture */
1336 return 1 + first;
1337 }
1338
1339 int
allocFragmentParameters(FragmentAttrib * attrib,int nParam)1340 allocFragmentParameters (FragmentAttrib *attrib,
1341 int nParam)
1342 {
1343 int first = attrib->nParam;
1344
1345 attrib->nParam += nParam;
1346
1347 return first;
1348 }
1349
1350 void
addFragmentFunction(FragmentAttrib * attrib,int function)1351 addFragmentFunction (FragmentAttrib *attrib,
1352 int function)
1353 {
1354 if (attrib->nFunction < MAX_FRAGMENT_FUNCTIONS)
1355 attrib->function[attrib->nFunction++] = function;
1356 }
1357
1358 void
initFragmentAttrib(FragmentAttrib * attrib,const WindowPaintAttrib * paint)1359 initFragmentAttrib (FragmentAttrib *attrib,
1360 const WindowPaintAttrib *paint)
1361 {
1362 attrib->opacity = paint->opacity;
1363 attrib->brightness = paint->brightness;
1364 attrib->saturation = paint->saturation;
1365 attrib->nTexture = 0;
1366 attrib->nFunction = 0;
1367 attrib->nParam = 0;
1368
1369 memset (attrib->function, 0, sizeof (attrib->function));
1370 }
1371
1372 Bool
enableFragmentAttrib(CompScreen * s,FragmentAttrib * attrib,Bool * blending)1373 enableFragmentAttrib (CompScreen *s,
1374 FragmentAttrib *attrib,
1375 Bool *blending)
1376 {
1377 GLuint name;
1378 GLenum type;
1379 Bool programBlending;
1380
1381 if (!s->fragmentProgram)
1382 return FALSE;
1383
1384 name = getFragmentProgram (s, attrib, &type, &programBlending);
1385 if (!name)
1386 return FALSE;
1387
1388 *blending = !programBlending;
1389
1390 glEnable (GL_FRAGMENT_PROGRAM_ARB);
1391
1392 (*s->bindProgram) (type, name);
1393
1394 return TRUE;
1395 }
1396
1397 void
disableFragmentAttrib(CompScreen * s,FragmentAttrib * attrib)1398 disableFragmentAttrib (CompScreen *s,
1399 FragmentAttrib *attrib)
1400 {
1401 glDisable (GL_FRAGMENT_PROGRAM_ARB);
1402 }
1403