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 {
161
FunctionId function[MAX_FRAGMENT_FUNCTIONS];
166
typedef boost::function<void (BodyOp *, int)> DataOpCallBack;
168
class InitialLoadFunction : public Function {
170
InitialLoadFunction ()
173
name = "__core_load";
174
mask = COMP_FUNCTION_MASK;
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);
186
static InitialLoadFunction initialLoadFunction;
189
findFragmentFunction (GLScreen *s,
192
foreach (Function *f, s->fragmentStorage ()->functions)
199
findFragmentFunctionWithName (GLScreen *s,
202
foreach (Function *f, s->fragmentStorage ()->functions)
203
if (f->name.compare (name) == 0)
209
findFragmentProgram (GLScreen *s,
210
FunctionId *signature,
211
unsigned int nSignature)
215
foreach (Program *p, s->fragmentStorage ()->programs)
217
if (p->signature.size () != nSignature)
220
for (i = 0; i < nSignature; i++)
221
if (signature[i] != p->signature[i])
231
functionMaskToType (int mask)
237
{ COMP_FUNCTION_TYPE_ARB, COMP_FUNCTION_ARB_MASK }
242
for (i = 0; i < sizeof (maskToType) / sizeof (maskToType[0]); i++)
243
if (mask & maskToType[i].mask)
244
return maskToType[i].type;
250
forEachDataOpInFunction (std::vector<Function *> list,
254
CompString loadOffset,
257
DataOpCallBack callBack)
259
Function *f = list[index];
261
bool colorDone = false;
262
bool blendDone = false;
267
foreach (BodyOp &bodyOp, f->data[type].body)
269
switch (bodyOp.type) {
271
CompString offset = loadOffset;
274
if (bodyOp.data.size ())
276
if (loadOffset.size ())
278
dataOp.type = OpTypeDataOffset;
280
compPrintf ("ADD __tmp_texcoord%d, %s, %s;",
281
index, loadOffset.c_str (),
282
bodyOp.data.c_str ());
284
callBack (&dataOp, index);
286
offset = compPrintf ("__tmp_texcoord%d", index);
290
offset = bodyOp.data;
294
forEachDataOpInFunction (list, index - 1, type,
296
offset, &colorDone, &blendDone,
299
if (bodyOp.dst.compare("output"))
301
dataOp.type = OpTypeDataStore;
303
compPrintf ("MOV %s, output;", bodyOp.dst.c_str ());
305
/* move to destination */
306
callBack (&dataOp, index);
310
if (loadOffset.size ())
312
dataOp.type = OpTypeDataOffset;
314
compPrintf ("ADD __tmp_texcoord0, fragment.texcoord[0], %s;",
315
loadOffset.c_str ());
317
callBack (&dataOp, index);
319
dataOp.data = bodyOp.offset[loadTarget];
323
dataOp.data = bodyOp.noOffset[loadTarget];
326
dataOp.type = OpTypeData;
328
callBack (&dataOp, index);
334
dataOp.type = OpTypeData;
336
compPrintf ("MUL %s, fragment.color, %s;",
338
bodyOp.src.c_str ());
340
callBack (&dataOp, index);
342
else if (bodyOp.dst.compare (bodyOp.src))
344
dataOp.type = OpTypeData;
346
compPrintf ("MOV %s, %s;",
348
bodyOp.src.c_str ());
350
callBack (&dataOp, index);
354
case OpTypeDataBlend:
358
callBack (&bodyOp, index);
360
case OpTypeDataStore:
361
case OpTypeDataOffset:
362
case OpTypeHeaderTemp:
363
case OpTypeHeaderParam:
364
case OpTypeHeaderAttrib:
377
forEachHeaderOpWithType (std::vector<HeaderOp> list,
381
CompString functionPrefix,
383
DataOpCallBack callBack)
387
dataOp.type = OpTypeData;
389
foreach (HeaderOp &header, list)
391
if (header.type == type)
399
dataOp.data = prefix;
402
dataOp.data += functionPrefix;
404
dataOp.data += header.name;
405
callBack (&dataOp, index);
415
forEachDataOp (std::vector<Function *> list,
417
DataOpCallBack callBack)
422
int count, nList = list.size ();
424
dataOp.type = OpTypeData;
428
dataOp.data = "TEMP output";
430
callBack (&dataOp, nList);
432
foreach (Function *f, list)
433
count = forEachHeaderOpWithType (f->data[type].header,
434
nList, OpTypeHeaderTemp,
435
"", f->name, count, callBack);
439
callBack (&dataOp, nList);
443
foreach (Function *f, list)
444
count = forEachHeaderOpWithType (f->data[type].header,
445
nList, OpTypeHeaderParam,
446
"PARAM ", f->name, count,
453
callBack (&dataOp, nList);
458
foreach (Function *f, list)
459
count = forEachHeaderOpWithType (f->data[type].header,
460
nList, OpTypeHeaderAttrib,
461
"ATTRIB ", f->name, count,
468
callBack (&dataOp, nList);
471
forEachDataOpInFunction (list, nList - 1, type, 0, "",
472
&colorDone, &blendDone,
476
dataOp.data = "MOV result.color, output;END";
478
dataOp.data = "MUL result.color, fragment.color, output;END";
480
callBack (&dataOp, nList);
486
addFetchOffsetVariables (BodyOp *op,
491
if (op->type == OpTypeDataOffset)
495
data->append (compPrintf ("TEMP __tmp_texcoord%d;", index));
496
indices[index] = true;
505
data->append (op->data);
509
buildFragmentProgram (GLScreen *s,
510
PrivateAttrib *attrib)
513
std::vector<Function *> functionList (1);
514
int mask = COMP_FUNCTION_MASK;
517
CompString fetchData;
518
bool indices[MAX_FRAGMENT_FUNCTIONS];
521
program = new Program ();
525
functionList[0] = &initialLoadFunction;
527
for (i = 0; i < attrib->nFunction; i++)
529
Function *f = findFragmentFunction (s, attrib->function[i]);
532
functionList.push_back (f);
535
foreach (Function *f, functionList)
540
compLogMessage ("opengl", CompLogLevelWarn,
541
"fragment functions can't be linked together "
542
"because a common type doesn't exist");
545
if (!mask || functionList.size () == 1)
551
for (i = 0; i < attrib->nFunction; i++)
552
program->signature.push_back (attrib->function[i]);
554
type = functionMaskToType (mask);
556
fetchData = "!!ARBfp1.0";
558
foreach (bool &val, indices)
561
forEachDataOp (functionList, type,
562
boost::bind (addFetchOffsetVariables, _1, _2, indices, &fetchData));
564
program->blending = forEachDataOp (functionList, type,
565
boost::bind (addData, _1, &fetchData));
567
program->type = GL_FRAGMENT_PROGRAM_ARB;
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 ());
577
glGetIntegerv (GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
578
if (glGetError () != GL_NO_ERROR || errorPos != -1)
580
compLogMessage ("opengl", CompLogLevelError,
581
"failed to load fragment program");
583
(*GL::deletePrograms) (1, &program->name);
593
getFragmentProgram (GLScreen *s,
594
PrivateAttrib *attrib,
600
if (!attrib->nFunction)
603
program = findFragmentProgram (s, attrib->function, attrib->nFunction);
606
program = buildFragmentProgram (s, attrib);
609
s->fragmentStorage ()->programs.push_back (program);
615
*type = program->type;
616
*blending = program->blending;
618
return program->name;
625
/* performs simple variable substitution */
627
copyData (std::vector<HeaderOp> header,
628
const CompString prefix,
631
CompString inPrefix (prefix);
634
foreach (HeaderOp &h, header)
636
size_t pos = data.find (h.name);
637
while (pos != std::string::npos)
639
data.insert (pos,inPrefix);
640
pos += inPrefix.size () + h.name.size ();
641
pos = data.find (h.name, pos);
648
PrivateFunctionData::PrivateFunctionData (const PrivateFunctionData& src,
649
CompString dstPrefix) :
654
foreach (BodyOp b, src.body)
661
dst.dst = copyData (header, dstPrefix, b.dst);
663
dst.data = copyData (header, dstPrefix, b.data);
667
dst.target = b.target;
670
case OpTypeHeaderTemp:
671
case OpTypeHeaderParam:
672
case OpTypeHeaderAttrib:
675
case OpTypeDataBlend:
676
case OpTypeDataStore:
677
case OpTypeDataOffset:
678
dst.data = copyData (header, dstPrefix, b.data);
681
dst.dst = copyData (header, dstPrefix, b.dst);
682
dst.src = copyData (header, dstPrefix, b.src);
685
body.push_back (dst);
690
addHeaderOpToFunctionData (PrivateFunctionData *data,
694
static const char *reserved[] = {
706
foreach (const char *word, reserved)
708
if (n.find (word) != std::string::npos)
710
compLogMessage ("opengl", CompLogLevelWarn,
711
"%s is a reserved word", word);
719
data->header.push_back (header);
724
FunctionData::FunctionData () :
725
priv (new PrivateFunctionData ())
729
FunctionData::~FunctionData ()
735
FunctionData::status ()
741
FunctionData::addTempHeaderOp (const char *name)
744
addHeaderOpToFunctionData (priv, name, OpTypeHeaderTemp);
748
FunctionData::addParamHeaderOp (const char *name)
751
addHeaderOpToFunctionData (priv, name, OpTypeHeaderParam);
755
FunctionData::addAttribHeaderOp (const char *name)
758
addHeaderOpToFunctionData (priv, name, OpTypeHeaderAttrib);
763
FunctionData::addFetchOp (const char *dst, const char *offset, int target)
767
b.type = OpTypeFetch;
768
b.dst = CompString (dst);
772
b.data = CompString (offset);
774
b.data = CompString ("");
776
priv->body.push_back (b);
780
FunctionData::addColorOp (const char *dst, const char *src)
784
b.type = OpTypeColor;
785
b.dst = CompString (dst);
786
b.src = CompString (src);
788
priv->body.push_back (b);
792
FunctionData::addDataOp (const char *str, ...)
799
b.data = compPrintf(str, ap);
802
priv->body.push_back (b);
806
FunctionData::addBlendOp (const char *str, ...)
811
b.type = OpTypeDataBlend;
813
b.data = compPrintf(str, ap);
816
priv->body.push_back (b);
820
FunctionData::createFragmentFunction (const char *name)
822
GLScreen *s = GLScreen::get (screen);
823
Function *function = new Function ();
824
CompString validName = name;
828
while (findFragmentFunctionWithName (s, validName))
830
validName = compPrintf ("%s%d", name, i++);
833
function->data[COMP_FUNCTION_TYPE_ARB] =
834
PrivateFunctionData (*priv, validName);
836
function->name = validName;
837
function->mask = COMP_FUNCTION_ARB_MASK;
838
function->id = s->fragmentStorage ()->lastFunctionId++;
840
s->fragmentStorage ()->functions.push_back (function);
845
Attrib::Attrib (const GLWindowPaintAttrib &paint) :
846
priv (new PrivateAttrib ())
848
priv->opacity = paint.opacity;
849
priv->brightness = paint.brightness;
850
priv->saturation = paint.saturation;
855
foreach (FunctionId &f, priv->function)
859
Attrib::Attrib (const Attrib &fa) :
860
priv (new PrivateAttrib ())
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;
869
for (int i = 0; i < MAX_FRAGMENT_FUNCTIONS; i++)
870
priv->function[i] = fa.priv->function[i];
879
Attrib::allocTextureUnits (unsigned int nTexture)
881
unsigned int first = priv->nTexture;
883
priv->nTexture += nTexture;
885
/* 0 is reserved for source texture */
890
Attrib::allocParameters (unsigned int nParam)
892
unsigned int first = priv->nParam;
894
priv->nParam += nParam;
900
Attrib::addFunction (FunctionId function)
902
if (priv->nFunction < MAX_FRAGMENT_FUNCTIONS)
903
priv->function[priv->nFunction++] = function;
907
Attrib::enable (bool *blending)
911
bool programBlending;
913
if (!GL::fragmentProgram)
916
name = getFragmentProgram (GLScreen::get (screen), priv, &type,
921
*blending = !programBlending;
923
glEnable (GL_FRAGMENT_PROGRAM_ARB);
925
(*GL::bindProgram) (type, name);
933
glDisable (GL_FRAGMENT_PROGRAM_ARB);
937
Attrib::getSaturation ()
939
return priv->saturation;
943
Attrib::getBrightness ()
945
return priv->brightness;
949
Attrib::getOpacity ()
951
return priv->opacity;
955
Attrib::setSaturation (unsigned short value)
957
priv->saturation = value;
961
Attrib::setBrightness (unsigned short value)
963
priv->brightness = value;
968
Attrib::setOpacity (unsigned short value)
970
priv->opacity = value;
974
Attrib::hasFunctions ()
976
return priv->nFunction > 0;
979
void destroyFragmentFunction (FunctionId id)
981
GLScreen *s = GLScreen::get (screen);
985
function = findFragmentFunction (s, id);
990
std::vector<Program *>::iterator it;
995
it = s->fragmentStorage ()->programs.begin ();
997
for (; it != s->fragmentStorage ()->programs.end (); it++)
999
foreach (FunctionId i, (*it)->signature)
1013
s->fragmentStorage ()->programs.erase (it);
1018
std::vector<Function *>::iterator fi =
1019
std::find (s->fragmentStorage ()->functions.begin (),
1020
s->fragmentStorage ()->functions.end (),
1022
if (fi != s->fragmentStorage ()->functions.end ())
1023
s->fragmentStorage ()->functions.erase (fi);
1029
getSaturateFragmentFunction (GLTexture *texture,
1033
GLScreen *s = GLScreen::get (screen);
1038
if (texture->target () == GL_TEXTURE_2D)
1039
target = COMP_FETCH_TARGET_2D;
1041
target = COMP_FETCH_TARGET_RECT;
1043
if (!s->fragmentStorage ()->saturateFunction [target][param])
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;";
1051
data.addTempHeaderOp ("temp");
1052
data.addFetchOp ("output", NULL, target);
1053
data.addColorOp ("output", "output");
1055
data.addDataOp (saturateData, param, param);
1057
if (!data.status ())
1060
s->fragmentStorage ()->saturateFunction [target][param] =
1061
data.createFragmentFunction ("__core_saturate");
1065
return s->fragmentStorage ()->saturateFunction [target][param];
1068
Storage::Storage () :
1073
for (int i = 0; i < 64; i++)
1075
saturateFunction[0][i] = 0;
1076
saturateFunction[1][i] = 0;
1080
Storage::~Storage ()
1082
foreach (Program *p, programs)
1085
foreach (Function *f, functions)