~mc-return/compiz/compiz.merge-src-screen.cpp-improvements

« back to all changes in this revision

Viewing changes to plugins/opengl/src/fragment.cpp

  • Committer: Dennis kasprzyk
  • Author(s): Dennis Kasprzyk
  • Date: 2009-03-15 05:09:18 UTC
  • Revision ID: git-v1:163f6b6f3c3b7764987cbdf8e03cc355edeaa499
New generalized build system.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <boost/function.hpp>
 
27
#include <boost/bind.hpp>
 
28
#include <boost/foreach.hpp>
 
29
#define foreach BOOST_FOREACH
 
30
 
 
31
#include <core/core.h>
 
32
#include <opengl/texture.h>
 
33
#include <opengl/fragment.h>
 
34
#include "privatefragment.h"
 
35
#include "privates.h"
 
36
 
 
37
#include <string.h>
 
38
#include <stdlib.h>
 
39
#include <stdarg.h>
 
40
 
 
41
#define COMP_FUNCTION_TYPE_ARB 0
 
42
#define COMP_FUNCTION_TYPE_NUM 1
 
43
 
 
44
#define COMP_FUNCTION_ARB_MASK (1 << 0)
 
45
#define COMP_FUNCTION_MASK     (COMP_FUNCTION_ARB_MASK)
 
46
 
 
47
namespace GLFragment {
 
48
 
 
49
    class Program {
 
50
        public:
 
51
            Program () :
 
52
                signature (0),
 
53
                blending (false),
 
54
                name (0),
 
55
                type (GL_FRAGMENT_PROGRAM_ARB)
 
56
            {};
 
57
            ~Program ()
 
58
            {
 
59
                if (name)
 
60
                    (*GL::deletePrograms) (1, &name);
 
61
            };
 
62
 
 
63
        public:
 
64
            std::vector<FunctionId> signature;
 
65
 
 
66
            bool blending;
 
67
 
 
68
            GLuint name;
 
69
            GLenum type;
 
70
    };
 
71
 
 
72
    typedef enum {
 
73
        OpTypeData,
 
74
        OpTypeDataStore,
 
75
        OpTypeDataOffset,
 
76
        OpTypeDataBlend,
 
77
        OpTypeHeaderTemp,
 
78
        OpTypeHeaderParam,
 
79
        OpTypeHeaderAttrib,
 
80
        OpTypeColor,
 
81
        OpTypeFetch,
 
82
        OpTypeLoad
 
83
    } OpType;
 
84
 
 
85
    class HeaderOp {
 
86
        public:
 
87
            HeaderOp () : type(OpTypeHeaderTemp), name ("") {};
 
88
        public:
 
89
            OpType     type;
 
90
            CompString name;
 
91
    };
 
92
 
 
93
    class BodyOp {
 
94
        public:
 
95
            BodyOp () :
 
96
                type(OpTypeData),
 
97
                data (""),
 
98
                dst (""),
 
99
                src (""),
 
100
                target (0)
 
101
            {
 
102
                foreach (CompString &str, noOffset)
 
103
                    str = "";
 
104
                foreach (CompString &str, offset)
 
105
                    str = "";
 
106
            };
 
107
 
 
108
        public:
 
109
            OpType       type;
 
110
            CompString   data;
 
111
            CompString   dst;
 
112
            CompString   src;
 
113
            unsigned int target;
 
114
            CompString   noOffset[COMP_FETCH_TARGET_NUM];
 
115
            CompString   offset[COMP_FETCH_TARGET_NUM];
 
116
 
 
117
    };
 
118
 
 
119
    class PrivateFunctionData {
 
120
        public:
 
121
            PrivateFunctionData () : header (0), body (0), status (true) {};
 
122
            PrivateFunctionData (const PrivateFunctionData&, CompString);
 
123
 
 
124
        public:
 
125
            std::vector<HeaderOp> header;
 
126
            std::vector<BodyOp>   body;
 
127
            bool                  status;
 
128
    };
 
129
 
 
130
    class Function {
 
131
        public:
 
132
            Function ():
 
133
                id (0),
 
134
                name (""),
 
135
                mask (0)
 
136
            {};
 
137
 
 
138
        public:
 
139
            FunctionId          id;
 
140
            CompString          name;
 
141
            PrivateFunctionData data[COMP_FUNCTION_TYPE_NUM];
 
142
            unsigned int        mask;
 
143
    };
 
144
 
 
145
    class PrivateAttrib {
 
146
        public:
 
147
            PrivateAttrib () :
 
148
                opacity (0xffff),
 
149
                brightness (0xffff),
 
150
                saturation (0xffff),
 
151
                nTexture (0),
 
152
                nFunction (0),
 
153
                nParam (0)
 
154
            {};
 
155
 
 
156
        public:
 
157
            GLushort   opacity;
 
158
            GLushort   brightness;
 
159
            GLushort   saturation;
 
160
            int        nTexture;
 
161
            FunctionId function[MAX_FRAGMENT_FUNCTIONS];
 
162
            int        nFunction;
 
163
            int        nParam;
 
164
    };
 
165
 
 
166
    typedef boost::function<void (BodyOp *, int)> DataOpCallBack;
 
167
 
 
168
    class InitialLoadFunction : public Function {
 
169
        public:
 
170
            InitialLoadFunction ()
 
171
            {
 
172
                id   = 0;
 
173
                name = "__core_load";
 
174
                mask = COMP_FUNCTION_MASK;
 
175
 
 
176
                BodyOp b;
 
177
                b.type = OpTypeLoad;
 
178
                b.noOffset[0] = "TEX output, fragment.texcoord[0], texture[0], 2D;";
 
179
                b.noOffset[1] = "TEX output, fragment.texcoord[0], texture[0], RECT;";
 
180
                b.offset[0] = "TEX output, __tmp_texcoord0, texture[0], 2D;";
 
181
                b.offset[1] = "TEX output, __tmp_texcoord0, texture[0], RECT;";
 
182
                data[0].body.push_back (b);
 
183
            };
 
184
    };
 
185
 
 
186
    static InitialLoadFunction initialLoadFunction;
 
187
 
 
188
    static Function *
 
189
    findFragmentFunction (GLScreen   *s,
 
190
                          FunctionId id)
 
191
    {
 
192
        foreach (Function *f, s->fragmentStorage ()->functions)
 
193
            if (f->id == id)
 
194
                return f;
 
195
        return NULL;
 
196
    }
 
197
 
 
198
    static Function *
 
199
    findFragmentFunctionWithName (GLScreen   *s,
 
200
                                  CompString name)
 
201
    {
 
202
        foreach (Function *f, s->fragmentStorage ()->functions)
 
203
            if (f->name.compare (name) == 0)
 
204
                return f;
 
205
        return NULL;
 
206
    }
 
207
 
 
208
    static Program *
 
209
    findFragmentProgram (GLScreen     *s,
 
210
                         FunctionId   *signature,
 
211
                         unsigned int nSignature)
 
212
    {
 
213
        unsigned int i;
 
214
 
 
215
        foreach (Program *p, s->fragmentStorage ()->programs)
 
216
        {
 
217
            if (p->signature.size () != nSignature)
 
218
                continue;
 
219
 
 
220
            for (i = 0; i < nSignature; i++)
 
221
                if (signature[i] != p->signature[i])
 
222
                    break;
 
223
 
 
224
            if (i == nSignature)
 
225
                return p;
 
226
        }
 
227
        return NULL;
 
228
    }
 
229
 
 
230
    static unsigned int
 
231
    functionMaskToType (int mask)
 
232
    {
 
233
        static struct {
 
234
            unsigned int type;
 
235
            unsigned int mask;
 
236
        } maskToType[] = {
 
237
            { COMP_FUNCTION_TYPE_ARB, COMP_FUNCTION_ARB_MASK }
 
238
        };
 
239
 
 
240
        unsigned int i;
 
241
 
 
242
        for (i = 0; i < sizeof (maskToType) / sizeof (maskToType[0]); i++)
 
243
            if (mask & maskToType[i].mask)
 
244
                return maskToType[i].type;
 
245
 
 
246
        return 0;
 
247
    }
 
248
 
 
249
    static void
 
250
    forEachDataOpInFunction (std::vector<Function *> list,
 
251
                             int                     index,
 
252
                             int                     type,
 
253
                             int                     loadTarget,
 
254
                             CompString              loadOffset,
 
255
                             bool                    *color,
 
256
                             bool                    *blend,
 
257
                             DataOpCallBack          callBack)
 
258
    {
 
259
        Function *f = list[index];
 
260
        BodyOp   dataOp;
 
261
        bool     colorDone = false;
 
262
        bool     blendDone = false;
 
263
 
 
264
        *color = false;
 
265
        *blend = false;
 
266
 
 
267
        foreach (BodyOp &bodyOp, f->data[type].body)
 
268
        {
 
269
            switch (bodyOp.type) {
 
270
                case OpTypeFetch: {
 
271
                    CompString offset = loadOffset;
 
272
 
 
273
                    /* add offset */
 
274
                    if (bodyOp.data.size ())
 
275
                    {
 
276
                        if (loadOffset.size ())
 
277
                        {
 
278
                            dataOp.type = OpTypeDataOffset;
 
279
                            dataOp.data =
 
280
                                compPrintf ("ADD __tmp_texcoord%d, %s, %s;",
 
281
                                            index, loadOffset.c_str (),
 
282
                                            bodyOp.data.c_str ());
 
283
 
 
284
                            callBack (&dataOp, index);
 
285
 
 
286
                            offset = compPrintf ("__tmp_texcoord%d", index);
 
287
                        }
 
288
                        else
 
289
                        {
 
290
                            offset = bodyOp.data;
 
291
                        }
 
292
                    }
 
293
 
 
294
                    forEachDataOpInFunction (list, index - 1, type,
 
295
                                            bodyOp.target,
 
296
                                            offset, &colorDone, &blendDone,
 
297
                                            callBack);
 
298
 
 
299
                    if (bodyOp.dst.compare("output"))
 
300
                    {
 
301
                        dataOp.type = OpTypeDataStore;
 
302
                        dataOp.data =
 
303
                            compPrintf ("MOV %s, output;", bodyOp.dst.c_str ());
 
304
 
 
305
                        /* move to destination */
 
306
                        callBack (&dataOp, index);
 
307
                    }
 
308
                } break;
 
309
                case OpTypeLoad:
 
310
                    if (loadOffset.size ())
 
311
                    {
 
312
                        dataOp.type = OpTypeDataOffset;
 
313
                        dataOp.data =
 
314
                            compPrintf ("ADD __tmp_texcoord0, fragment.texcoord[0], %s;",
 
315
                                        loadOffset.c_str ());
 
316
 
 
317
                        callBack (&dataOp, index);
 
318
 
 
319
                        dataOp.data = bodyOp.offset[loadTarget];
 
320
                    }
 
321
                    else
 
322
                    {
 
323
                        dataOp.data = bodyOp.noOffset[loadTarget];
 
324
                    }
 
325
 
 
326
                    dataOp.type = OpTypeData;
 
327
 
 
328
                    callBack (&dataOp, index);
 
329
 
 
330
                    break;
 
331
                case OpTypeColor:
 
332
                    if (!colorDone)
 
333
                    {
 
334
                        dataOp.type = OpTypeData;
 
335
                        dataOp.data =
 
336
                            compPrintf ("MUL %s, fragment.color, %s;",
 
337
                                        bodyOp.dst.c_str (),
 
338
                                        bodyOp.src.c_str ());
 
339
 
 
340
                        callBack (&dataOp, index);
 
341
                    }
 
342
                    else if (bodyOp.dst.compare (bodyOp.src))
 
343
                    {
 
344
                        dataOp.type = OpTypeData;
 
345
                        dataOp.data =
 
346
                            compPrintf ("MOV %s, %s;",
 
347
                                        bodyOp.dst.c_str (),
 
348
                                        bodyOp.src.c_str ());
 
349
 
 
350
                        callBack (&dataOp, index);
 
351
                    }
 
352
                    *color = true;
 
353
                    break;
 
354
                case OpTypeDataBlend:
 
355
                    *blend = true;
 
356
                    /* fall-through */
 
357
                case OpTypeData:
 
358
                    callBack (&bodyOp, index);
 
359
                    break;
 
360
                case OpTypeDataStore:
 
361
                case OpTypeDataOffset:
 
362
                case OpTypeHeaderTemp:
 
363
                case OpTypeHeaderParam:
 
364
                case OpTypeHeaderAttrib:
 
365
                    break;
 
366
            }
 
367
        }
 
368
 
 
369
        if (colorDone)
 
370
            *color = true;
 
371
 
 
372
        if (blendDone)
 
373
            *blend = true;
 
374
    }
 
375
 
 
376
    static int
 
377
    forEachHeaderOpWithType (std::vector<HeaderOp> list,
 
378
                             int                   index,
 
379
                             OpType                type,
 
380
                             CompString            prefix,
 
381
                             CompString            functionPrefix,
 
382
                             int                   count,
 
383
                             DataOpCallBack        callBack)
 
384
    {
 
385
        BodyOp dataOp;
 
386
 
 
387
        dataOp.type = OpTypeData;
 
388
 
 
389
        foreach (HeaderOp &header, list)
 
390
        {
 
391
            if (header.type == type)
 
392
            {
 
393
                if (count)
 
394
                {
 
395
                    dataOp.data = ", ";
 
396
                }
 
397
                else
 
398
                {
 
399
                    dataOp.data = prefix;
 
400
                }
 
401
 
 
402
                dataOp.data += functionPrefix;
 
403
                dataOp.data += "_";
 
404
                dataOp.data += header.name;
 
405
                callBack (&dataOp, index);
 
406
 
 
407
                count++;
 
408
            }
 
409
        }
 
410
 
 
411
        return count;
 
412
    }
 
413
 
 
414
    static bool
 
415
    forEachDataOp (std::vector<Function *> list,
 
416
                   int                     type,
 
417
                   DataOpCallBack          callBack)
 
418
    {
 
419
        BodyOp dataOp;
 
420
        bool   colorDone;
 
421
        bool   blendDone;
 
422
        int    count, nList = list.size ();
 
423
 
 
424
        dataOp.type = OpTypeData;
 
425
 
 
426
        count = 1;
 
427
 
 
428
        dataOp.data = "TEMP output";
 
429
 
 
430
        callBack (&dataOp, nList);
 
431
 
 
432
        foreach (Function *f, list)
 
433
            count = forEachHeaderOpWithType (f->data[type].header,
 
434
                                             nList, OpTypeHeaderTemp,
 
435
                                             "", f->name, count, callBack);
 
436
 
 
437
        dataOp.data = ";";
 
438
 
 
439
        callBack (&dataOp, nList);
 
440
 
 
441
        count = 0;
 
442
 
 
443
        foreach (Function *f, list)
 
444
            count = forEachHeaderOpWithType (f->data[type].header,
 
445
                                             nList, OpTypeHeaderParam,
 
446
                                             "PARAM ", f->name, count,
 
447
                                             callBack);
 
448
 
 
449
        if (count)
 
450
        {
 
451
            dataOp.data = ";";
 
452
 
 
453
            callBack (&dataOp, nList);
 
454
        }
 
455
 
 
456
        count = 0;
 
457
 
 
458
        foreach (Function *f, list)
 
459
            count = forEachHeaderOpWithType (f->data[type].header,
 
460
                                             nList, OpTypeHeaderAttrib,
 
461
                                             "ATTRIB ", f->name, count,
 
462
                                             callBack);
 
463
 
 
464
        if (count)
 
465
        {
 
466
            dataOp.data = ";";
 
467
 
 
468
            callBack (&dataOp, nList);
 
469
        }
 
470
 
 
471
        forEachDataOpInFunction (list, nList - 1, type, 0, "",
 
472
                                 &colorDone, &blendDone,
 
473
                                 callBack);
 
474
 
 
475
        if (colorDone)
 
476
            dataOp.data = "MOV result.color, output;END";
 
477
        else
 
478
            dataOp.data = "MUL result.color, fragment.color, output;END";
 
479
 
 
480
        callBack (&dataOp, nList);
 
481
 
 
482
        return blendDone;
 
483
    }
 
484
 
 
485
    static void
 
486
    addFetchOffsetVariables (BodyOp     *op,
 
487
                             int        index,
 
488
                             bool       *indices,
 
489
                             CompString *data)
 
490
    {
 
491
        if (op->type == OpTypeDataOffset)
 
492
        {
 
493
            if (!indices[index])
 
494
            {
 
495
                data->append (compPrintf ("TEMP __tmp_texcoord%d;", index));
 
496
                indices[index] = true;
 
497
            }
 
498
        }
 
499
    }
 
500
 
 
501
    static void
 
502
    addData (BodyOp     *op,
 
503
             CompString *data)
 
504
    {
 
505
        data->append (op->data);
 
506
    }
 
507
 
 
508
    static Program *
 
509
    buildFragmentProgram (GLScreen      *s,
 
510
                          PrivateAttrib *attrib)
 
511
    {
 
512
        Program                 *program;
 
513
        std::vector<Function *> functionList (1);
 
514
        int                     mask = COMP_FUNCTION_MASK;
 
515
        int                     type;
 
516
        GLint                   errorPos;
 
517
        CompString fetchData;
 
518
        bool       indices[MAX_FRAGMENT_FUNCTIONS];
 
519
        int        i;
 
520
 
 
521
        program = new Program ();
 
522
        if (!program)
 
523
            return NULL;
 
524
 
 
525
        functionList[0] = &initialLoadFunction;
 
526
 
 
527
        for (i = 0; i < attrib->nFunction; i++)
 
528
        {
 
529
            Function *f = findFragmentFunction (s, attrib->function[i]);
 
530
 
 
531
            if (f)
 
532
                functionList.push_back (f);
 
533
        }
 
534
 
 
535
        foreach (Function *f, functionList)
 
536
            mask &= f->mask;
 
537
 
 
538
        if (!mask)
 
539
        {
 
540
            compLogMessage ("opengl", CompLogLevelWarn,
 
541
                            "fragment functions can't be linked together "
 
542
                            "because a common type doesn't exist");
 
543
        }
 
544
 
 
545
        if (!mask || functionList.size () == 1)
 
546
        {
 
547
            delete program;
 
548
            return NULL;
 
549
        }
 
550
 
 
551
        for (i = 0; i < attrib->nFunction; i++)
 
552
            program->signature.push_back (attrib->function[i]);
 
553
 
 
554
        type = functionMaskToType (mask);
 
555
 
 
556
        fetchData = "!!ARBfp1.0";
 
557
 
 
558
        foreach (bool &val, indices)
 
559
            val = false;
 
560
 
 
561
        forEachDataOp (functionList, type,
 
562
            boost::bind (addFetchOffsetVariables, _1, _2, indices, &fetchData));
 
563
 
 
564
        program->blending = forEachDataOp (functionList, type,
 
565
                                boost::bind (addData, _1, &fetchData));
 
566
 
 
567
        program->type = GL_FRAGMENT_PROGRAM_ARB;
 
568
 
 
569
        glGetError ();
 
570
 
 
571
        (*GL::genPrograms) (1, &program->name);
 
572
        (*GL::bindProgram) (GL_FRAGMENT_PROGRAM_ARB, program->name);
 
573
        (*GL::programString) (GL_FRAGMENT_PROGRAM_ARB,
 
574
                              GL_PROGRAM_FORMAT_ASCII_ARB,
 
575
                              fetchData.size (), fetchData.c_str ());
 
576
 
 
577
        glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
 
578
        if (glGetError () != GL_NO_ERROR || errorPos != -1)
 
579
        {
 
580
            compLogMessage ("opengl", CompLogLevelError,
 
581
                            "failed to load fragment program");
 
582
 
 
583
            (*GL::deletePrograms) (1, &program->name);
 
584
 
 
585
            program->name = 0;
 
586
            program->type = 0;
 
587
        }
 
588
 
 
589
        return program;
 
590
    }
 
591
 
 
592
    static GLuint
 
593
    getFragmentProgram (GLScreen      *s,
 
594
                        PrivateAttrib *attrib,
 
595
                        GLenum        *type,
 
596
                        bool          *blending)
 
597
    {
 
598
        Program *program;
 
599
 
 
600
        if (!attrib->nFunction)
 
601
            return 0;
 
602
 
 
603
        program = findFragmentProgram (s, attrib->function, attrib->nFunction);
 
604
        if (!program)
 
605
        {
 
606
            program = buildFragmentProgram (s, attrib);
 
607
            if (program)
 
608
            {
 
609
                s->fragmentStorage ()->programs.push_back (program);
 
610
            }
 
611
        }
 
612
 
 
613
        if (program)
 
614
        {
 
615
            *type     = program->type;
 
616
            *blending = program->blending;
 
617
 
 
618
            return program->name;
 
619
        }
 
620
 
 
621
        return 0;
 
622
    }
 
623
 
 
624
 
 
625
    /* performs simple variable substitution */
 
626
    static CompString
 
627
    copyData (std::vector<HeaderOp> header,
 
628
              const CompString      prefix,
 
629
              CompString            data)
 
630
    {
 
631
        CompString inPrefix (prefix);
 
632
        inPrefix += "_";
 
633
 
 
634
        foreach (HeaderOp &h, header)
 
635
        {
 
636
            size_t pos = data.find (h.name);
 
637
            while (pos != std::string::npos)
 
638
            {
 
639
                data.insert (pos,inPrefix);
 
640
                pos += inPrefix.size () + h.name.size ();
 
641
                pos = data.find (h.name, pos);
 
642
            }
 
643
        }
 
644
 
 
645
        return data;
 
646
    }
 
647
 
 
648
    PrivateFunctionData::PrivateFunctionData (const PrivateFunctionData& src,
 
649
                                              CompString dstPrefix) :
 
650
        header (src.header),
 
651
        body (0)
 
652
    {
 
653
 
 
654
        foreach (BodyOp b, src.body)
 
655
        {
 
656
            BodyOp dst;
 
657
            dst.type = b.type;
 
658
 
 
659
            switch (b.type) {
 
660
                case OpTypeFetch:
 
661
                    dst.dst = copyData (header, dstPrefix, b.dst);
 
662
                    if (b.data.size ())
 
663
                        dst.data = copyData (header, dstPrefix, b.data);
 
664
                    else
 
665
                        dst.data = "";
 
666
 
 
667
                    dst.target = b.target;
 
668
                    break;
 
669
                case OpTypeLoad:
 
670
                case OpTypeHeaderTemp:
 
671
                case OpTypeHeaderParam:
 
672
                case OpTypeHeaderAttrib:
 
673
                    break;
 
674
                case OpTypeData:
 
675
                case OpTypeDataBlend:
 
676
                case OpTypeDataStore:
 
677
                case OpTypeDataOffset:
 
678
                    dst.data = copyData (header, dstPrefix, b.data);
 
679
                    break;
 
680
                case OpTypeColor:
 
681
                    dst.dst = copyData (header, dstPrefix, b.dst);
 
682
                    dst.src = copyData (header, dstPrefix, b.src);
 
683
                    break;
 
684
                }
 
685
            body.push_back (dst);
 
686
        }
 
687
    }
 
688
 
 
689
    static bool
 
690
    addHeaderOpToFunctionData (PrivateFunctionData *data,
 
691
                               const char          *name,
 
692
                               OpType              type)
 
693
    {
 
694
        static const char *reserved[] = {
 
695
            "output",
 
696
            "__tmp_texcoord",
 
697
            "fragment",
 
698
            "program",
 
699
            "result",
 
700
            "state",
 
701
            "texture"
 
702
        };
 
703
        HeaderOp   header;
 
704
        CompString n (name);
 
705
 
 
706
        foreach (const char *word, reserved)
 
707
        {
 
708
            if (n.find (word) != std::string::npos)
 
709
            {
 
710
                compLogMessage ("opengl", CompLogLevelWarn,
 
711
                                "%s is a reserved word", word);
 
712
                return false;
 
713
            }
 
714
        }
 
715
 
 
716
 
 
717
        header.type = type;
 
718
        header.name = n;
 
719
        data->header.push_back (header);
 
720
 
 
721
        return true;
 
722
    }
 
723
 
 
724
    FunctionData::FunctionData () :
 
725
        priv (new PrivateFunctionData ())
 
726
    {
 
727
    }
 
728
 
 
729
    FunctionData::~FunctionData ()
 
730
    {
 
731
        delete priv;
 
732
    }
 
733
 
 
734
    bool
 
735
    FunctionData::status ()
 
736
    {
 
737
        return priv->status;
 
738
    }
 
739
 
 
740
    void
 
741
    FunctionData::addTempHeaderOp (const char *name)
 
742
    {
 
743
        priv->status &=
 
744
            addHeaderOpToFunctionData (priv, name, OpTypeHeaderTemp);
 
745
    }
 
746
 
 
747
    void
 
748
    FunctionData::addParamHeaderOp (const char *name)
 
749
    {
 
750
        priv->status &=
 
751
            addHeaderOpToFunctionData (priv, name, OpTypeHeaderParam);
 
752
    }
 
753
 
 
754
    void
 
755
    FunctionData::addAttribHeaderOp (const char *name)
 
756
    {
 
757
        priv->status &=
 
758
            addHeaderOpToFunctionData (priv, name, OpTypeHeaderAttrib);
 
759
    }
 
760
 
 
761
 
 
762
    void
 
763
    FunctionData::addFetchOp (const char *dst, const char *offset, int target)
 
764
    {
 
765
        BodyOp b;
 
766
 
 
767
        b.type   = OpTypeFetch;
 
768
        b.dst    = CompString (dst);
 
769
        b.target = target;
 
770
 
 
771
        if (offset)
 
772
            b.data = CompString (offset);
 
773
        else
 
774
            b.data = CompString ("");
 
775
 
 
776
        priv->body.push_back (b);
 
777
    }
 
778
 
 
779
    void
 
780
    FunctionData::addColorOp (const char *dst, const char *src)
 
781
    {
 
782
        BodyOp b;
 
783
        
 
784
        b.type = OpTypeColor;
 
785
        b.dst  = CompString (dst);
 
786
        b.src  = CompString (src);
 
787
 
 
788
        priv->body.push_back (b);
 
789
    }
 
790
 
 
791
    void
 
792
    FunctionData::addDataOp (const char *str, ...)
 
793
    {
 
794
        BodyOp  b;
 
795
        va_list ap;
 
796
        
 
797
        b.type = OpTypeData;
 
798
        va_start (ap, str);
 
799
        b.data = compPrintf(str, ap);
 
800
        va_end (ap);
 
801
        
 
802
        priv->body.push_back (b);
 
803
    }
 
804
 
 
805
    void
 
806
    FunctionData::addBlendOp (const char *str, ...)
 
807
    {
 
808
        BodyOp  b;
 
809
        va_list ap;
 
810
        
 
811
        b.type = OpTypeDataBlend;
 
812
        va_start (ap, str);
 
813
        b.data = compPrintf(str, ap);
 
814
        va_end (ap);
 
815
        
 
816
        priv->body.push_back (b);
 
817
    }
 
818
 
 
819
    FunctionId
 
820
    FunctionData::createFragmentFunction (const char *name)
 
821
    {
 
822
        GLScreen     *s = GLScreen::get (screen);
 
823
        Function     *function = new Function ();
 
824
        CompString   validName = name;
 
825
        unsigned int i = 0;
 
826
 
 
827
        
 
828
        while (findFragmentFunctionWithName (s, validName))
 
829
        {
 
830
            validName = compPrintf ("%s%d", name, i++);
 
831
        }
 
832
 
 
833
        function->data[COMP_FUNCTION_TYPE_ARB] =
 
834
            PrivateFunctionData (*priv, validName);
 
835
 
 
836
        function->name = validName;
 
837
        function->mask = COMP_FUNCTION_ARB_MASK;
 
838
        function->id   = s->fragmentStorage ()->lastFunctionId++;
 
839
 
 
840
        s->fragmentStorage ()->functions.push_back (function);
 
841
 
 
842
        return function->id;
 
843
    }
 
844
 
 
845
    Attrib::Attrib (const GLWindowPaintAttrib &paint) :
 
846
        priv (new PrivateAttrib ())
 
847
    {
 
848
        priv->opacity    = paint.opacity;
 
849
        priv->brightness = paint.brightness;
 
850
        priv->saturation = paint.saturation;
 
851
        priv->nTexture   = 0;
 
852
        priv->nFunction  = 0;
 
853
        priv->nParam     = 0;
 
854
 
 
855
        foreach (FunctionId &f, priv->function)
 
856
            f = 0;
 
857
    };
 
858
 
 
859
    Attrib::Attrib (const Attrib &fa) :
 
860
        priv (new PrivateAttrib ())
 
861
    {
 
862
        priv->opacity    = fa.priv->opacity;
 
863
        priv->brightness = fa.priv->brightness;
 
864
        priv->saturation = fa.priv->saturation;
 
865
        priv->nTexture   = fa.priv->nTexture;
 
866
        priv->nFunction  = fa.priv->nFunction;
 
867
        priv->nParam     = fa.priv->nParam;
 
868
 
 
869
        for (int i = 0; i < MAX_FRAGMENT_FUNCTIONS; i++)
 
870
            priv->function[i] = fa.priv->function[i];
 
871
    }
 
872
 
 
873
    Attrib::~Attrib ()
 
874
    {
 
875
        delete priv;
 
876
    }
 
877
 
 
878
    unsigned int
 
879
    Attrib::allocTextureUnits (unsigned int nTexture)
 
880
    {
 
881
        unsigned int first = priv->nTexture;
 
882
 
 
883
        priv->nTexture += nTexture;
 
884
 
 
885
        /* 0 is reserved for source texture */
 
886
        return 1 + first;
 
887
    }
 
888
 
 
889
    unsigned int
 
890
    Attrib::allocParameters (unsigned int nParam)
 
891
    {
 
892
        unsigned int first = priv->nParam;
 
893
 
 
894
        priv->nParam += nParam;
 
895
 
 
896
        return first;
 
897
    }
 
898
 
 
899
    void
 
900
    Attrib::addFunction (FunctionId function)
 
901
    {
 
902
        if (priv->nFunction < MAX_FRAGMENT_FUNCTIONS)
 
903
            priv->function[priv->nFunction++] = function;
 
904
    }
 
905
 
 
906
    bool
 
907
    Attrib::enable (bool *blending)
 
908
    {
 
909
        GLuint name;
 
910
        GLenum type;
 
911
        bool   programBlending;
 
912
 
 
913
        if (!GL::fragmentProgram)
 
914
            return false;
 
915
 
 
916
        name = getFragmentProgram (GLScreen::get (screen), priv, &type,
 
917
                                   &programBlending);
 
918
        if (!name)
 
919
            return false;
 
920
 
 
921
        *blending = !programBlending;
 
922
 
 
923
        glEnable (GL_FRAGMENT_PROGRAM_ARB);
 
924
 
 
925
        (*GL::bindProgram) (type, name);
 
926
 
 
927
        return true;
 
928
    }
 
929
 
 
930
    void
 
931
    Attrib::disable ()
 
932
    {
 
933
        glDisable (GL_FRAGMENT_PROGRAM_ARB);
 
934
    }
 
935
 
 
936
    unsigned short
 
937
    Attrib::getSaturation ()
 
938
    {
 
939
        return priv->saturation;
 
940
    }
 
941
 
 
942
    unsigned short
 
943
    Attrib::getBrightness ()
 
944
    {
 
945
        return priv->brightness;
 
946
    }
 
947
 
 
948
    unsigned short
 
949
    Attrib::getOpacity ()
 
950
    {
 
951
        return priv->opacity;
 
952
    }
 
953
 
 
954
    void
 
955
    Attrib::setSaturation (unsigned short value)
 
956
    {
 
957
        priv->saturation = value;
 
958
    }
 
959
 
 
960
    void
 
961
    Attrib::setBrightness (unsigned short value)
 
962
        {
 
963
        priv->brightness = value;
 
964
    }
 
965
 
 
966
 
 
967
    void
 
968
    Attrib::setOpacity (unsigned short value)
 
969
    {
 
970
        priv->opacity = value;
 
971
    }
 
972
 
 
973
    bool
 
974
    Attrib::hasFunctions ()
 
975
    {
 
976
        return priv->nFunction > 0;
 
977
    }
 
978
 
 
979
    void destroyFragmentFunction (FunctionId id)
 
980
    {
 
981
        GLScreen *s = GLScreen::get (screen);
 
982
        Function *function;
 
983
        Program  *program;
 
984
 
 
985
        function = findFragmentFunction (s, id);
 
986
 
 
987
        if (!function)
 
988
            return;
 
989
 
 
990
        std::vector<Program *>::iterator it;
 
991
 
 
992
        do {
 
993
            program = NULL;
 
994
 
 
995
            it = s->fragmentStorage ()->programs.begin ();
 
996
 
 
997
            for (; it != s->fragmentStorage ()->programs.end (); it++)
 
998
            {
 
999
                foreach (FunctionId i, (*it)->signature)
 
1000
                    if (i == id)
 
1001
                    {
 
1002
                        program = (*it);
 
1003
                        break;
 
1004
                    }
 
1005
 
 
1006
                if (program)
 
1007
                    break;
 
1008
            }
 
1009
 
 
1010
            if (program)
 
1011
            {
 
1012
                delete program;
 
1013
                s->fragmentStorage ()->programs.erase (it);
 
1014
            }
 
1015
 
 
1016
        } while (program);
 
1017
 
 
1018
        std::vector<Function *>::iterator fi =
 
1019
            std::find (s->fragmentStorage ()->functions.begin (),
 
1020
                       s->fragmentStorage ()->functions.end (),
 
1021
                       function);
 
1022
        if (fi != s->fragmentStorage ()->functions.end ())
 
1023
            s->fragmentStorage ()->functions.erase (fi);
 
1024
 
 
1025
        delete (function);
 
1026
    }
 
1027
 
 
1028
    FunctionId
 
1029
    getSaturateFragmentFunction (GLTexture *texture,
 
1030
                                 int         param)
 
1031
    {
 
1032
        int      target;
 
1033
        GLScreen *s = GLScreen::get (screen);
 
1034
 
 
1035
        if (param >= 64)
 
1036
            return 0;
 
1037
 
 
1038
        if (texture->target () == GL_TEXTURE_2D)
 
1039
            target = COMP_FETCH_TARGET_2D;
 
1040
        else
 
1041
            target = COMP_FETCH_TARGET_RECT;
 
1042
 
 
1043
        if (!s->fragmentStorage ()->saturateFunction [target][param])
 
1044
        {
 
1045
            static const char *saturateData =
 
1046
                "MUL temp, output, { 1.0, 1.0, 1.0, 0.0 };"
 
1047
                "DP3 temp, temp, program.env[%d];"
 
1048
                "LRP output.xyz, program.env[%d].w, output, temp;";
 
1049
            FunctionData  data;
 
1050
 
 
1051
            data.addTempHeaderOp ("temp");
 
1052
            data.addFetchOp ("output", NULL, target);
 
1053
            data.addColorOp ("output", "output");
 
1054
 
 
1055
            data.addDataOp (saturateData, param, param);
 
1056
 
 
1057
            if (!data.status ())
 
1058
                return 0;
 
1059
 
 
1060
            s->fragmentStorage ()->saturateFunction [target][param] =
 
1061
                data.createFragmentFunction ("__core_saturate");
 
1062
 
 
1063
        }
 
1064
 
 
1065
        return s->fragmentStorage ()->saturateFunction [target][param];
 
1066
    }
 
1067
 
 
1068
    Storage::Storage () :
 
1069
        lastFunctionId (1),
 
1070
        functions (0),
 
1071
        programs (0)
 
1072
    {
 
1073
        for (int i = 0; i < 64; i++)
 
1074
        {
 
1075
            saturateFunction[0][i] = 0;
 
1076
            saturateFunction[1][i] = 0;
 
1077
        }
 
1078
    }
 
1079
 
 
1080
    Storage::~Storage ()
 
1081
    {
 
1082
        foreach (Program *p, programs)
 
1083
            delete p;
 
1084
        programs.clear ();
 
1085
        foreach (Function *f, functions)
 
1086
            delete f;
 
1087
        functions.clear ();
 
1088
    }
 
1089
 
 
1090
};