2
* Copyright © 2007 Novell, Inc.
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
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.
23
* Author: David Reveman <davidr@novell.com>
26
#include <boost/function.hpp>
27
#include <boost/bind.hpp>
28
#include <boost/foreach.hpp>
29
#define foreach BOOST_FOREACH
31
#include <core/core.h>
32
#include <opengl/texture.h>
33
#include <opengl/fragment.h>
34
#include "privatefragment.h"
41
#define COMP_FUNCTION_TYPE_ARB 0
42
#define COMP_FUNCTION_TYPE_NUM 1
44
#define COMP_FUNCTION_ARB_MASK (1 << 0)
45
#define COMP_FUNCTION_MASK (COMP_FUNCTION_ARB_MASK)
47
namespace GLFragment {
55
type (GL_FRAGMENT_PROGRAM_ARB)
60
(*GL::deletePrograms) (1, &name);
64
std::vector<FunctionId> signature;
87
HeaderOp () : type (OpTypeHeaderTemp), name ("") {};
102
foreach (CompString &str, noOffset)
104
foreach (CompString &str, offset)
114
CompString noOffset[COMP_FETCH_TARGET_NUM];
115
CompString offset[COMP_FETCH_TARGET_NUM];
119
class PrivateFunctionData {
121
PrivateFunctionData () : header (0), body (0), status (true) {};
122
PrivateFunctionData (const PrivateFunctionData&, CompString);
125
std::vector<HeaderOp> header;
126
std::vector<BodyOp> body;
141
PrivateFunctionData data[COMP_FUNCTION_TYPE_NUM];
145
class PrivateAttrib {
156
PrivateAttrib (const PrivateAttrib &pa) :
157
opacity (pa.opacity),
158
brightness (pa.brightness),
159
saturation (pa.saturation),
160
nTexture (pa.nTexture),
161
nFunction (pa.nFunction),
164
for (int i = 0; i < MAX_FRAGMENT_FUNCTIONS; i++)
165
function[i] = pa.function[i];
173
FunctionId function[MAX_FRAGMENT_FUNCTIONS];
178
typedef boost::function<void (BodyOp *, int)> DataOpCallBack;
180
class InitialLoadFunction : public Function {
182
InitialLoadFunction ()
185
name = "__core_load";
186
mask = COMP_FUNCTION_MASK;
190
b.noOffset[0] = "TEX output, fragment.texcoord[0], texture[0], 2D;";
191
b.noOffset[1] = "TEX output, fragment.texcoord[0], texture[0], RECT;";
192
b.offset[0] = "TEX output, __tmp_texcoord0, texture[0], 2D;";
193
b.offset[1] = "TEX output, __tmp_texcoord0, texture[0], RECT;";
194
data[0].body.push_back (b);
198
static InitialLoadFunction initialLoadFunction;
201
findFragmentFunction (GLScreen *s,
204
foreach (Function *f, s->fragmentStorage ()->functions)
211
findFragmentFunctionWithName (GLScreen *s,
214
foreach (Function *f, s->fragmentStorage ()->functions)
215
if (f->name.compare (name) == 0)
221
findFragmentProgram (GLScreen *s,
222
FunctionId *signature,
223
unsigned int nSignature)
227
foreach (Program *p, s->fragmentStorage ()->programs)
229
if (p->signature.size () != nSignature)
232
for (i = 0; i < nSignature; i++)
233
if (signature[i] != p->signature[i])
243
functionMaskToType (int mask)
249
{ COMP_FUNCTION_TYPE_ARB, COMP_FUNCTION_ARB_MASK }
254
for (i = 0; i < sizeof (maskToType) / sizeof (maskToType[0]); i++)
255
if (mask & maskToType[i].mask)
256
return maskToType[i].type;
262
forEachDataOpInFunction (std::vector<Function *> list,
266
CompString loadOffset,
269
DataOpCallBack callBack)
271
Function *f = list[index];
273
bool colorDone = false;
274
bool blendDone = false;
279
foreach (BodyOp &bodyOp, f->data[type].body)
281
switch (bodyOp.type) {
283
CompString offset = loadOffset;
286
if (bodyOp.data.size ())
288
if (loadOffset.size ())
290
dataOp.type = OpTypeDataOffset;
292
compPrintf ("ADD __tmp_texcoord%d, %s, %s;",
293
index, loadOffset.c_str (),
294
bodyOp.data.c_str ());
296
callBack (&dataOp, index);
298
offset = compPrintf ("__tmp_texcoord%d", index);
302
offset = bodyOp.data;
306
forEachDataOpInFunction (list, index - 1, type,
308
offset, &colorDone, &blendDone,
311
if (bodyOp.dst.compare ("output"))
313
dataOp.type = OpTypeDataStore;
315
compPrintf ("MOV %s, output;", bodyOp.dst.c_str ());
317
/* move to destination */
318
callBack (&dataOp, index);
322
if (loadOffset.size ())
324
dataOp.type = OpTypeDataOffset;
326
compPrintf ("ADD __tmp_texcoord0, fragment.texcoord[0], %s;",
327
loadOffset.c_str ());
329
callBack (&dataOp, index);
331
dataOp.data = bodyOp.offset[loadTarget];
335
dataOp.data = bodyOp.noOffset[loadTarget];
338
dataOp.type = OpTypeData;
340
callBack (&dataOp, index);
346
dataOp.type = OpTypeData;
348
compPrintf ("MUL %s, fragment.color, %s;",
350
bodyOp.src.c_str ());
352
callBack (&dataOp, index);
354
else if (bodyOp.dst.compare (bodyOp.src))
356
dataOp.type = OpTypeData;
358
compPrintf ("MOV %s, %s;",
360
bodyOp.src.c_str ());
362
callBack (&dataOp, index);
366
case OpTypeDataBlend:
370
callBack (&bodyOp, index);
372
case OpTypeDataStore:
373
case OpTypeDataOffset:
374
case OpTypeHeaderTemp:
375
case OpTypeHeaderParam:
376
case OpTypeHeaderAttrib:
389
forEachHeaderOpWithType (std::vector<HeaderOp> list,
393
CompString functionPrefix,
395
DataOpCallBack callBack)
399
dataOp.type = OpTypeData;
401
foreach (HeaderOp &header, list)
403
if (header.type == type)
411
dataOp.data = prefix;
414
dataOp.data += functionPrefix;
416
dataOp.data += header.name;
418
callBack (&dataOp, index);
428
forEachDataOp (std::vector<Function *> list,
430
DataOpCallBack callBack)
435
int count, nList = list.size ();
437
dataOp.type = OpTypeData;
441
dataOp.data = "TEMP output";
443
callBack (&dataOp, nList);
445
foreach (Function *f, list)
446
count = forEachHeaderOpWithType (f->data[type].header,
447
nList, OpTypeHeaderTemp,
448
"", f->name, count, callBack);
452
callBack (&dataOp, nList);
456
foreach (Function *f, list)
457
count = forEachHeaderOpWithType (f->data[type].header,
458
nList, OpTypeHeaderParam,
459
"PARAM ", f->name, count,
466
callBack (&dataOp, nList);
471
foreach (Function *f, list)
472
count = forEachHeaderOpWithType (f->data[type].header,
473
nList, OpTypeHeaderAttrib,
474
"ATTRIB ", f->name, count,
481
callBack (&dataOp, nList);
484
forEachDataOpInFunction (list, nList - 1, type, 0, "",
485
&colorDone, &blendDone,
489
dataOp.data = "MOV result.color, output;END";
491
dataOp.data = "MUL result.color, fragment.color, output;END";
493
callBack (&dataOp, nList);
499
addFetchOffsetVariables (BodyOp *op,
504
if (op->type == OpTypeDataOffset)
508
data->append (compPrintf ("TEMP __tmp_texcoord%d;", index));
509
indices[index] = true;
518
data->append (op->data);
522
buildFragmentProgram (GLScreen *s,
523
PrivateAttrib *attrib)
526
std::vector<Function *> functionList (1);
527
int mask = COMP_FUNCTION_MASK;
531
CompString fetchData;
532
bool indices[MAX_FRAGMENT_FUNCTIONS];
535
program = new Program ();
539
functionList[0] = &initialLoadFunction;
541
for (i = 0; i < attrib->nFunction; i++)
543
Function *f = findFragmentFunction (s, attrib->function[i]);
546
functionList.push_back (f);
549
foreach (Function *f, functionList)
554
compLogMessage ("opengl", CompLogLevelWarn,
555
"fragment functions can't be linked together "
556
"because a common type doesn't exist");
559
if (!mask || functionList.size () == 1)
565
for (i = 0; i < attrib->nFunction; i++)
566
program->signature.push_back (attrib->function[i]);
568
type = functionMaskToType (mask);
570
fetchData = "!!ARBfp1.0";
572
foreach (bool &val, indices)
575
forEachDataOp (functionList, type,
576
boost::bind (addFetchOffsetVariables, _1, _2, indices, &fetchData));
578
program->blending = forEachDataOp (functionList, type,
579
boost::bind (addData, _1, &fetchData));
581
program->type = GL_FRAGMENT_PROGRAM_ARB;
585
(*GL::genPrograms) (1, &program->name);
586
(*GL::bindProgram) (GL_FRAGMENT_PROGRAM_ARB, program->name);
587
(*GL::programString) (GL_FRAGMENT_PROGRAM_ARB,
588
GL_PROGRAM_FORMAT_ASCII_ARB,
589
fetchData.size (), fetchData.c_str ());
591
glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
592
errorType = glGetError ();
593
if (errorType != GL_NO_ERROR || errorPos != -1)
595
compLogMessage ("opengl", CompLogLevelError,
596
"failed to load fragment program");
598
(*GL::deletePrograms) (1, &program->name);
608
getFragmentProgram (GLScreen *s,
609
PrivateAttrib *attrib,
615
if (!attrib->nFunction)
618
program = findFragmentProgram (s, attrib->function, attrib->nFunction);
621
program = buildFragmentProgram (s, attrib);
624
s->fragmentStorage ()->programs.push_back (program);
630
*type = program->type;
631
*blending = program->blending;
633
return program->name;
640
/* performs simple variable substitution */
642
copyData (std::vector<HeaderOp> header,
643
const CompString prefix,
646
CompString inPrefix (prefix);
649
foreach (HeaderOp &h, header)
651
size_t pos = data.find (h.name);
652
while (pos != std::string::npos)
654
bool prependPrefix = false;
655
/* It is possible to match parts of words here, so
656
* make sure that we have found the next chunk in the
657
* string and not just a header which matches
658
* part of another word */
659
if (data.size () > pos + h.name.size ())
661
const CompString &token = data.substr (pos + h.name.size (), 1);
666
prependPrefix = true;
670
/* We matched part of another word as our
671
* token so search for the next whole
673
pos = data.find (h.name, pos + 1);
678
/* If this is the last word in the string, then it must
679
* have matched exactly our header op, so it is ok
680
* to prepend a prefix here and go straight to
681
* std::string::npos */
682
prependPrefix = true;
687
/* prepend the header op prefix to the header op
688
* and seek past this word to the next instance
689
* of the unprepended header op */
690
data.insert (pos, inPrefix);
691
pos += inPrefix.size () + h.name.size ();
692
pos = data.find (h.name, pos);
700
PrivateFunctionData::PrivateFunctionData (const PrivateFunctionData& src,
701
CompString dstPrefix) :
707
foreach (BodyOp b, src.body)
714
dst.dst = copyData (header, dstPrefix, b.dst);
716
dst.data = copyData (header, dstPrefix, b.data);
720
dst.target = b.target;
723
case OpTypeHeaderTemp:
724
case OpTypeHeaderParam:
725
case OpTypeHeaderAttrib:
728
case OpTypeDataBlend:
729
case OpTypeDataStore:
730
case OpTypeDataOffset:
731
dst.data = copyData (header, dstPrefix, b.data);
734
dst.dst = copyData (header, dstPrefix, b.dst);
735
dst.src = copyData (header, dstPrefix, b.src);
738
body.push_back (dst);
743
addHeaderOpToFunctionData (PrivateFunctionData *data,
747
static const char *reserved[] = {
759
foreach (const char *word, reserved)
761
if (n.find (word) != std::string::npos)
763
compLogMessage ("opengl", CompLogLevelWarn,
764
"%s is a reserved word", word);
772
data->header.push_back (header);
777
FunctionData::FunctionData () :
778
priv (new PrivateFunctionData ())
782
FunctionData::~FunctionData ()
788
FunctionData::status ()
794
FunctionData::addTempHeaderOp (const char *name)
797
addHeaderOpToFunctionData (priv, name, OpTypeHeaderTemp);
801
FunctionData::addParamHeaderOp (const char *name)
804
addHeaderOpToFunctionData (priv, name, OpTypeHeaderParam);
808
FunctionData::addAttribHeaderOp (const char *name)
811
addHeaderOpToFunctionData (priv, name, OpTypeHeaderAttrib);
816
FunctionData::addFetchOp (const char *dst, const char *offset, int target)
820
b.type = OpTypeFetch;
821
b.dst = CompString (dst);
825
b.data = CompString (offset);
827
b.data = CompString ("");
829
priv->body.push_back (b);
833
FunctionData::addColorOp (const char *dst, const char *src)
837
b.type = OpTypeColor;
838
b.dst = CompString (dst);
839
b.src = CompString (src);
841
priv->body.push_back (b);
845
FunctionData::addDataOp (const char *str, ...)
852
b.data = compPrintf (str, ap);
855
priv->body.push_back (b);
859
FunctionData::addBlendOp (const char *str, ...)
864
b.type = OpTypeDataBlend;
866
b.data = compPrintf (str, ap);
869
priv->body.push_back (b);
873
FunctionData::createFragmentFunction (const char *name)
875
GLScreen *s = GLScreen::get (screen);
876
Function *function = new Function ();
877
CompString validName = name;
880
while (findFragmentFunctionWithName (s, validName))
882
validName = compPrintf ("%s%d", name, i++);
885
function->data[COMP_FUNCTION_TYPE_ARB] =
886
PrivateFunctionData (*priv, validName);
888
function->name = validName;
889
function->mask = COMP_FUNCTION_ARB_MASK;
890
function->id = s->fragmentStorage ()->lastFunctionId++;
892
s->fragmentStorage ()->functions.push_back (function);
897
Attrib::Attrib (const GLWindowPaintAttrib &paint) :
898
priv (new PrivateAttrib ())
900
priv->opacity = paint.opacity;
901
priv->brightness = paint.brightness;
902
priv->saturation = paint.saturation;
907
foreach (FunctionId &f, priv->function)
911
Attrib::Attrib (const Attrib &fa) :
912
priv (new PrivateAttrib (*fa.priv))
922
Attrib::operator= (const Attrib &rhs)
924
if (this == &rhs) // Check for self-assignment
928
priv = new PrivateAttrib (*rhs.priv);
934
Attrib::allocTextureUnits (unsigned int nTexture)
936
unsigned int first = priv->nTexture;
938
priv->nTexture += nTexture;
940
/* 0 is reserved for source texture */
945
Attrib::allocParameters (unsigned int nParam)
947
unsigned int first = priv->nParam;
949
priv->nParam += nParam;
955
Attrib::addFunction (FunctionId function)
957
if (priv->nFunction < MAX_FRAGMENT_FUNCTIONS)
958
priv->function[priv->nFunction++] = function;
962
Attrib::enable (bool *blending)
966
bool programBlending;
968
if (!GL::fragmentProgram)
971
name = getFragmentProgram (GLScreen::get (screen), priv, &type,
976
*blending = !programBlending;
978
glEnable (GL_FRAGMENT_PROGRAM_ARB);
980
(*GL::bindProgram) (type, name);
988
glDisable (GL_FRAGMENT_PROGRAM_ARB);
992
Attrib::getSaturation ()
994
return priv->saturation;
998
Attrib::getBrightness ()
1000
return priv->brightness;
1004
Attrib::getOpacity ()
1006
return priv->opacity;
1010
Attrib::setSaturation (unsigned short value)
1012
priv->saturation = value;
1016
Attrib::setBrightness (unsigned short value)
1018
priv->brightness = value;
1023
Attrib::setOpacity (unsigned short value)
1025
priv->opacity = value;
1029
Attrib::hasFunctions ()
1031
return priv->nFunction > 0;
1034
void destroyFragmentFunction (FunctionId id)
1036
GLScreen *s = GLScreen::get (screen);
1040
function = findFragmentFunction (s, id);
1045
std::vector<Program *>::iterator it;
1050
it = s->fragmentStorage ()->programs.begin ();
1052
for (; it != s->fragmentStorage ()->programs.end (); it++)
1054
foreach (FunctionId i, (*it)->signature)
1068
s->fragmentStorage ()->programs.erase (it);
1073
std::vector<Function *>::iterator fi =
1074
std::find (s->fragmentStorage ()->functions.begin (),
1075
s->fragmentStorage ()->functions.end (),
1077
if (fi != s->fragmentStorage ()->functions.end ())
1078
s->fragmentStorage ()->functions.erase (fi);
1084
getSaturateFragmentFunction (GLTexture *texture,
1088
GLScreen *s = GLScreen::get (screen);
1093
if (texture->target () == GL_TEXTURE_2D)
1094
target = COMP_FETCH_TARGET_2D;
1096
target = COMP_FETCH_TARGET_RECT;
1098
if (!s->fragmentStorage ()->saturateFunction [target][param])
1100
static const char *saturateData =
1101
"MUL temp, output, { 1.0, 1.0, 1.0, 0.0 };"
1102
"DP3 temp, temp, program.env[%d];"
1103
"LRP output.xyz, program.env[%d].w, output, temp;";
1106
data.addTempHeaderOp ("temp");
1107
data.addFetchOp ("output", NULL, target);
1108
data.addColorOp ("output", "output");
1110
data.addDataOp (saturateData, param, param);
1112
if (!data.status ())
1115
s->fragmentStorage ()->saturateFunction [target][param] =
1116
data.createFragmentFunction ("__core_saturate");
1120
return s->fragmentStorage ()->saturateFunction [target][param];
1123
Storage::Storage () :
1128
for (int i = 0; i < 64; i++)
1130
saturateFunction[0][i] = 0;
1131
saturateFunction[1][i] = 0;
1135
Storage::~Storage ()
1137
foreach (Program *p, programs)
1140
foreach (Function *f, functions)