source: trunk/src/gpu/shader.cpp @ 2291

Last change on this file since 2291 was 2291, checked in by sam, 7 years ago

gpu: fix PS3 compilation caused by wrong function names.

  • Property svn:keywords set to Id
File size: 26.3 KB
RevLine 
[659]1//
2// Lol Engine
3//
[2216]4// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
[659]5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
[2183]8//   http://www.wtfpl.net/ for more details.
[659]9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
[775]15#include <cstring>
16#include <cstdio>
[659]17
18#ifdef WIN32
19#   define WIN32_LEAN_AND_MEAN
20#   include <windows.h>
[1208]21#   if defined USE_D3D9
[1212]22#       include <algorithm>
23        using std::min;
24        using std::max;
[1208]25#       include <d3d9.h>
26#       include <d3dx9shader.h>
27#   endif
[659]28#endif
29
30#include "core.h"
[673]31#include "lolgl.h"
[659]32
[818]33using namespace std;
34
[1208]35#if defined USE_D3D9
36extern IDirect3DDevice9 *g_d3ddevice;
37#elif defined _XBOX
38extern D3DDevice *g_d3ddevice;
39#endif
40
[686]41namespace lol
42{
43
[659]44/*
45 * Shader implementation class
46 */
47
48class ShaderData
49{
50    friend class Shader;
51
52private:
[1208]53#if defined USE_D3D9
54    IDirect3DVertexShader9 *vert_shader;
55    IDirect3DPixelShader9 *frag_shader;
56    ID3DXConstantTable *vert_table, *frag_table;
57#elif defined _XBOX
[1179]58    D3DVertexShader *vert_shader;
59    D3DPixelShader *frag_shader;
60    ID3DXConstantTable *vert_table, *frag_table;
[1174]61#elif !defined __CELLOS_LV2__
[659]62    GLuint prog_id, vert_id, frag_id;
[828]63#else
64    CGprogram vert_id, frag_id;
65#endif
[670]66    uint32_t vert_crc, frag_crc;
67
[775]68    /* Shader patcher */
69    static int GetVersion();
[778]70    static void Patch(char *dst, char const *vert, char const *frag);
[775]71
[670]72    /* Global shader cache */
73    static Shader *shaders[];
[2097]74    static Hash<char const *> hash;
[670]75    static int nshaders;
[659]76};
77
[670]78Shader *ShaderData::shaders[256];
[2097]79Hash<char const *> ShaderData::hash;
[670]80int ShaderData::nshaders = 0;
81
[659]82/*
83 * Public Shader class
84 */
85
[1385]86Shader *Shader::Create(char const *lolfx)
87{
88    char *src = new char[strlen(lolfx) + 2];
89    memcpy(src + 1, lolfx, strlen(lolfx) + 1);
90    src[0] = '\n';
91
92    /* Parse the crap */
93    Array<char const *, char const *> sections;
94    char *key = NULL;
95    for (char *parser = src; *parser; )
96    {
97        if (key == NULL && (parser[0] == '\n' || parser[0] == '\r')
[1928]98             && parser[1] == '[')
[1385]99        {
100            *parser = '\0';
[1928]101            parser += 2;
[1385]102            key = parser;
103        }
[1928]104        else if (key && parser[0] == ']')
[1385]105        {
106            *parser++ = '\0';
107        }
108        else if (key && (parser[0] == '\n' || parser[0] == '\r'))
109        {
110            sections.Push(key, parser);
111            parser++;
112            key = NULL;
113        }
114        else
115        {
116            parser++;
117        }
118    }
119
120    char const *vert = NULL, *frag = NULL;
121    for (int i = 0; i < sections.Count(); i++)
122    {
123#if !defined __CELLOS_LV2__ && !defined _XBOX && !defined USE_D3D9
[1928]124        if (!strcmp(sections[i].m1, "vert.glsl"))
[1385]125            vert = sections[i].m2;
[1928]126        if (!strcmp(sections[i].m1, "frag.glsl"))
[1385]127            frag = sections[i].m2;
128#else
[1928]129        if (!strcmp(sections[i].m1, "vert.hlsl"))
[1385]130            vert = sections[i].m2;
[1928]131        if (!strcmp(sections[i].m1, "frag.hlsl"))
[1385]132            frag = sections[i].m2;
133#endif
134    }
135
[1928]136    /* FIXME: we don’t know how to handle these yet. */
137    if (!vert)
138        Log::Error("no vertex shader found… sorry, I’m gonna crash now.\n");
139    if (!frag)
140        Log::Error("no fragment shader found… sorry, I’m gonna crash now.\n");
141
[2097]142    uint32_t new_vert_crc = ShaderData::hash(vert);
143    uint32_t new_frag_crc = ShaderData::hash(frag);
[670]144
145    for (int n = 0; n < ShaderData::nshaders; n++)
146    {
147        if (ShaderData::shaders[n]->data->vert_crc == new_vert_crc
148             && ShaderData::shaders[n]->data->frag_crc == new_frag_crc)
[1849]149        {
150            delete[] src;
[670]151            return ShaderData::shaders[n];
[1849]152        }
[670]153    }
154
155    Shader *ret = new Shader(vert, frag);
156    ShaderData::shaders[ShaderData::nshaders] = ret;
157    ShaderData::nshaders++;
[1849]158
159    delete[] src;
[670]160    return ret;
[668]161}
162
163void Shader::Destroy(Shader *shader)
164{
[670]165    /* XXX: do nothing! the shader should remain in cache */
166    (void)shader;
[668]167}
168
[659]169Shader::Shader(char const *vert, char const *frag)
170  : data(new ShaderData())
171{
[1208]172#if defined USE_D3D9 || defined _XBOX
[1179]173    ID3DXBuffer *shader_code, *error_msg;
174    HRESULT hr;
[1389]175    D3DXMACRO macros[] =
176    {
177#if defined _XBOX
178        { "_XBOX", "1" },
179#endif
180        { NULL, NULL }
181    };
[1179]182#elif !defined __CELLOS_LV2__
[776]183    char buf[4096], errbuf[4096];
[775]184    char const *shader = buf;
[799]185    GLint status;
[659]186    GLsizei len;
[828]187#else
188    /* Initialise the runtime shader compiler. FIXME: this needs only
189     * to be done once. */
190    cgRTCgcInit();
191#endif
[659]192
[776]193    /* Compile vertex shader */
[2097]194    data->vert_crc = ShaderData::hash(vert);
[1208]195#if defined USE_D3D9 || defined _XBOX
[1389]196    hr = D3DXCompileShader(vert, (UINT)strlen(vert), macros, NULL, "main",
[1826]197                           "vs_3_0", 0, &shader_code, &error_msg,
[1179]198                           &data->vert_table);
199    if (FAILED(hr))
200    {
201        Log::Error("failed to compile vertex shader: %s",
202                   error_msg ? error_msg->GetBufferPointer() : "error");
203        Log::Error("shader source:\n%s\n", vert);
204    }
205    g_d3ddevice->CreateVertexShader((DWORD *)shader_code->GetBufferPointer(),
206                                    &data->vert_shader);
207    shader_code->Release();
208#elif !defined __CELLOS_LV2__
[778]209    ShaderData::Patch(buf, vert, NULL);
[659]210    data->vert_id = glCreateShader(GL_VERTEX_SHADER);
[775]211    glShaderSource(data->vert_id, 1, &shader, NULL);
[659]212    glCompileShader(data->vert_id);
213
[1470]214    glGetShaderInfoLog(data->vert_id, sizeof(errbuf), &len, errbuf);
[799]215    glGetShaderiv(data->vert_id, GL_COMPILE_STATUS, &status);
216    if (status != GL_TRUE)
[776]217    {
218        Log::Error("failed to compile vertex shader: %s", errbuf);
219        Log::Error("shader source:\n%s\n", buf);
220    }
[1690]221    else if (len > 16)
[1470]222    {
223        Log::Debug("compile log for vertex shader: %s", errbuf);
224        Log::Debug("shader source:\n%s\n", buf);
225    }
[828]226#else
227    data->vert_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, vert,
228                                    cgGLGetLatestProfile(CG_GL_VERTEX),
229                                    NULL, NULL);
230    if (data->vert_id == NULL)
231    {
232        Log::Error("failed to compile vertex shader");
233        Log::Error("shader source:\n%s\n", vert);
234    }
235#endif
[659]236
[776]237    /* Compile fragment shader */
[2097]238    data->frag_crc = ShaderData::hash(frag);
[1208]239#if defined USE_D3D9 || defined _XBOX
[1389]240    hr = D3DXCompileShader(frag, (UINT)strlen(frag), macros, NULL, "main",
[1826]241                           "ps_3_0", 0, &shader_code, &error_msg,
[1179]242                           &data->frag_table);
243    if (FAILED(hr))
244    {
245        Log::Error("failed to compile fragment shader: %s",
246                   error_msg ? error_msg->GetBufferPointer() : "error");
247        Log::Error("shader source:\n%s\n", frag);
248    }
249    g_d3ddevice->CreatePixelShader((DWORD *)shader_code->GetBufferPointer(),
250                                   &data->frag_shader);
251    shader_code->Release();
252#elif !defined __CELLOS_LV2__
[778]253    ShaderData::Patch(buf, NULL, frag);
[659]254    data->frag_id = glCreateShader(GL_FRAGMENT_SHADER);
[775]255    glShaderSource(data->frag_id, 1, &shader, NULL);
[659]256    glCompileShader(data->frag_id);
257
[1470]258    glGetShaderInfoLog(data->frag_id, sizeof(errbuf), &len, errbuf);
[799]259    glGetShaderiv(data->frag_id, GL_COMPILE_STATUS, &status);
260    if (status != GL_TRUE)
[776]261    {
262        Log::Error("failed to compile fragment shader: %s", errbuf);
263        Log::Error("shader source:\n%s\n", buf);
264    }
[1690]265    else if (len > 16)
[1470]266    {
267        Log::Debug("compile log for fragment shader: %s", errbuf);
268        Log::Debug("shader source:\n%s\n", buf);
269    }
[828]270#else
271    data->frag_id = cgCreateProgram(cgCreateContext(), CG_SOURCE, frag,
272                                    cgGLGetLatestProfile(CG_GL_FRAGMENT),
273                                    NULL, NULL);
274    if (data->frag_id == NULL)
275    {
276        Log::Error("failed to compile fragment shader");
277        Log::Error("shader source:\n%s\n", frag);
278    }
279#endif
[659]280
[1214]281#if defined USE_D3D9 || defined _XBOX
282    /* FIXME: this is only debug code, we don't need it. */
283    D3DXCONSTANTTABLE_DESC desc;
284    data->frag_table->GetDesc(&desc);
285    for (int i = 0; i < desc.Constants; i++)
286    {
287        D3DXCONSTANT_DESC cdesc;
288        UINT count = 1;
289        D3DXHANDLE h = data->frag_table->GetConstant(NULL, i);
290        data->frag_table->GetConstantDesc(h, &cdesc, &count);
291    }
292    data->vert_table->GetDesc(&desc);
293    for (int i = 0; i < desc.Constants; i++)
294    {
295        D3DXCONSTANT_DESC cdesc;
296        UINT count = 1;
297        D3DXHANDLE h = data->vert_table->GetConstant(NULL, i);
298        data->frag_table->GetConstantDesc(h, &cdesc, &count);
299    }
300#elif !defined __CELLOS_LV2__
[776]301    /* Create program */
[659]302    data->prog_id = glCreateProgram();
303    glAttachShader(data->prog_id, data->vert_id);
304    glAttachShader(data->prog_id, data->frag_id);
305
306    glLinkProgram(data->prog_id);
[1470]307    glGetProgramInfoLog(data->prog_id, sizeof(errbuf), &len, errbuf);
308    glGetProgramiv(data->prog_id, GL_LINK_STATUS, &status);
309    if (status != GL_TRUE)
310    {
311        Log::Error("failed to link program: %s", errbuf);
312    }
[1690]313    else if (len > 16)
[1470]314    {
315        Log::Debug("link log for program: %s", errbuf);
316    }
[659]317    glValidateProgram(data->prog_id);
[758]318#endif
[659]319}
320
[1227]321ShaderAttrib Shader::GetAttribLocation(char const *attr,
322                                       VertexUsage usage, int index) const
[659]323{
[1227]324    ShaderAttrib ret;
[1228]325    ret.m_flags = (uint64_t)(uint16_t)usage << 16;
326    ret.m_flags |= (uint64_t)(uint16_t)index;
[1208]327#if defined USE_D3D9 || defined _XBOX
[1179]328#elif !defined __CELLOS_LV2__
[2156]329    GLint l = glGetAttribLocation(data->prog_id, attr);
330    if (l < 0)
331    {
332        Log::Warn("tried to query invalid attribute: %s\n", attr);
333        l = 0;
334    }
335    ret.m_flags |= (uint64_t)(uint32_t)l << 32;
[828]336#else
[1228]337    /* FIXME: can we do this at all on the PS3? */
[758]338#endif
[1227]339    return ret;
[659]340}
341
[1214]342ShaderUniform Shader::GetUniformLocation(char const *uni) const
[659]343{
[1214]344    ShaderUniform ret;
[1208]345#if defined USE_D3D9 || defined _XBOX
[1214]346    /* Global variables are prefixed with "$" */
347    char tmpname[128];
348    sprintf(tmpname, "$%s", uni);
349    D3DXCONSTANT_DESC cdesc;
350    D3DXHANDLE hr;
351    UINT count;
352
353    count = 0;
354    hr = data->frag_table->GetConstantByName(NULL, tmpname);
355    if (hr)
356        data->frag_table->GetConstantDesc(hr, &cdesc, &count);
357    if (count)
358    {
359        ret.frag = cdesc.RegisterIndex;
360        ret.flags |= 1;
361    }
362
363    count = 0;
364    hr = data->vert_table->GetConstantByName(NULL, tmpname);
365    if (hr)
366        data->vert_table->GetConstantDesc(hr, &cdesc, &count);
367    if (count)
368    {
369        ret.vert = cdesc.RegisterIndex;
370        ret.flags |= 2;
371    }
[1179]372#elif !defined __CELLOS_LV2__
[1214]373    ret.frag = (uintptr_t)glGetUniformLocation(data->prog_id, uni);
374    ret.vert = 0;
[758]375#else
[1214]376    ret.frag = (uintptr_t)cgGetNamedParameter(data->frag_id, uni);
377    ret.vert = (uintptr_t)cgGetNamedParameter(data->vert_id, uni);
[758]378#endif
[1214]379    return ret;
[659]380}
381
[2288]382/*
383 * Uniform setters for scalars
384 */
385
[1215]386void Shader::SetUniform(ShaderUniform const &uni, int i)
387{
388#if defined USE_D3D9 || defined _XBOX
389    SetUniform(uni, ivec4(i, 0, 0, 0));
390#elif !defined __CELLOS_LV2__
391    glUniform1i(uni.frag, i);
392#else
[1289]393    /* FIXME: does this exist at all? cgGLSetParameter1i doesn't. */
[1215]394#endif
395}
396
397void Shader::SetUniform(ShaderUniform const &uni, ivec2 const &v)
398{
399#if defined USE_D3D9 || defined _XBOX
400    SetUniform(uni, ivec4(v, 0, 0));
401#elif !defined __CELLOS_LV2__
402    glUniform2i(uni.frag, v.x, v.y);
403#else
404    /* FIXME: does this exist at all? */
405#endif
406}
407
408void Shader::SetUniform(ShaderUniform const &uni, ivec3 const &v)
409{
410#if defined USE_D3D9 || defined _XBOX
411    SetUniform(uni, ivec4(v, 0));
412#elif !defined __CELLOS_LV2__
413    glUniform3i(uni.frag, v.x, v.y, v.z);
414#else
415    /* FIXME: does this exist at all? */
416#endif
417}
418
419void Shader::SetUniform(ShaderUniform const &uni, ivec4 const &v)
420{
421#if defined USE_D3D9 || defined _XBOX
[1221]422    if (uni.flags & 1)
423        g_d3ddevice->SetPixelShaderConstantI((UINT)uni.frag, &v[0], 1);
424    if (uni.flags & 2)
425        g_d3ddevice->SetVertexShaderConstantI((UINT)uni.vert, &v[0], 1);
[1215]426#elif !defined __CELLOS_LV2__
427    glUniform4i(uni.frag, v.x, v.y, v.z, v.w);
428#else
429    /* FIXME: does this exist at all? */
430#endif
431}
432
[1214]433void Shader::SetUniform(ShaderUniform const &uni, float f)
[832]434{
[1208]435#if defined USE_D3D9 || defined _XBOX
[1194]436    SetUniform(uni, vec4(f, 0, 0, 0));
[1179]437#elif !defined __CELLOS_LV2__
[1214]438    glUniform1f(uni.frag, f);
[832]439#else
[1214]440    if (uni.frag)
441        cgGLSetParameter1f((CGparameter)uni.frag, f);
442    if (uni.vert)
443        cgGLSetParameter1f((CGparameter)uni.vert, f);
[832]444#endif
445}
446
[1214]447void Shader::SetUniform(ShaderUniform const &uni, vec2 const &v)
[832]448{
[1208]449#if defined USE_D3D9 || defined _XBOX
[1194]450    SetUniform(uni, vec4(v, 0, 0));
[1179]451#elif !defined __CELLOS_LV2__
[1289]452    glUniform2fv(uni.frag, 1, &v[0]);
[832]453#else
[1214]454    if (uni.frag)
[1289]455        cgGLSetParameter2fv((CGparameter)uni.frag, &v[0]);
[1214]456    if (uni.vert)
[1289]457        cgGLSetParameter2fv((CGparameter)uni.vert, &v[0]);
[832]458#endif
459}
460
[1214]461void Shader::SetUniform(ShaderUniform const &uni, vec3 const &v)
[832]462{
[1208]463#if defined USE_D3D9 || defined _XBOX
[1194]464    SetUniform(uni, vec4(v, 0));
[1179]465#elif !defined __CELLOS_LV2__
[1289]466    glUniform3fv(uni.frag, 1, &v[0]);
[832]467#else
[1214]468    if (uni.frag)
[1289]469        cgGLSetParameter3fv((CGparameter)uni.frag, &v[0]);
[1214]470    if (uni.vert)
[1289]471        cgGLSetParameter3fv((CGparameter)uni.vert, &v[0]);
[832]472#endif
473}
474
[1214]475void Shader::SetUniform(ShaderUniform const &uni, vec4 const &v)
[832]476{
[1208]477#if defined USE_D3D9 || defined _XBOX
[1214]478    if (uni.flags & 1)
479        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &v[0], 1);
480    if (uni.flags & 2)
481        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &v[0], 1);
[1179]482#elif !defined __CELLOS_LV2__
[1289]483    glUniform4fv(uni.frag, 1, &v[0]);
[832]484#else
[1215]485    if (uni.frag)
[1289]486        cgGLSetParameter4fv((CGparameter)uni.frag, &v[0]);
[1215]487    if (uni.vert)
[1289]488        cgGLSetParameter4fv((CGparameter)uni.vert, &v[0]);
[832]489#endif
490}
491
[1259]492void Shader::SetUniform(ShaderUniform const &uni, mat2 const &m)
493{
494#if defined USE_D3D9 || defined _XBOX
[1265]495    /* FIXME: do we need padding here like for the mat3 version? */
[1259]496    if (uni.flags & 1)
497        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 1);
498    if (uni.flags & 2)
499        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 1);
500#elif !defined __CELLOS_LV2__
501    glUniformMatrix2fv(uni.frag, 1, GL_FALSE, &m[0][0]);
502#else
[1289]503    mat4 tmp(m, 1.0f, 1.0f);
504    if (uni.frag)
505        cgGLSetMatrixParameterfc((CGparameter)uni.frag, &m[0][0]);
506    if (uni.vert)
507        cgGLSetMatrixParameterfc((CGparameter)uni.vert, &m[0][0]);
[1259]508#endif
509}
510
511void Shader::SetUniform(ShaderUniform const &uni, mat3 const &m)
512{
513#if defined USE_D3D9 || defined _XBOX
[1265]514    /* Padding matrix columns is necessary on DirectX. We need to create
[1928]515     * a new data structure; a 4×4 matrix will do. */
[1265]516    mat4 tmp(m, 1.0f);
[1259]517    if (uni.flags & 1)
[1265]518        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &tmp[0][0], 3);
[1259]519    if (uni.flags & 2)
[1265]520        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &tmp[0][0], 3);
[1259]521#elif !defined __CELLOS_LV2__
522    glUniformMatrix3fv(uni.frag, 1, GL_FALSE, &m[0][0]);
523#else
[1289]524    /* FIXME: check it's the proper way to do this */
525    mat4 tmp(m, 1.0f);
526    if (uni.frag)
527        cgGLSetMatrixParameterfc((CGparameter)uni.frag, &m[0][0]);
528    if (uni.vert)
529        cgGLSetMatrixParameterfc((CGparameter)uni.vert, &m[0][0]);
[1259]530#endif
531}
532
[1214]533void Shader::SetUniform(ShaderUniform const &uni, mat4 const &m)
[832]534{
[1208]535#if defined USE_D3D9 || defined _XBOX
[1214]536    if (uni.flags & 1)
537        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag, &m[0][0], 4);
538    if (uni.flags & 2)
539        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert, &m[0][0], 4);
[1179]540#elif !defined __CELLOS_LV2__
[1215]541    glUniformMatrix4fv(uni.frag, 1, GL_FALSE, &m[0][0]);
[832]542#else
[1215]543    if (uni.frag)
544        cgGLSetMatrixParameterfc((CGparameter)uni.frag, &m[0][0]);
545    if (uni.vert)
546        cgGLSetMatrixParameterfc((CGparameter)uni.vert, &m[0][0]);
[832]547#endif
548}
549
[1773]550void Shader::SetUniform(ShaderUniform const &uni, ShaderTexture tex, int index)
[1452]551{
552#if defined USE_D3D9 || defined _XBOX
[1773]553    g_d3ddevice->SetTexture(index, (LPDIRECT3DTEXTURE9)tex.m_flags);
[1452]554#elif !defined __CELLOS_LV2__
555    glActiveTexture(GL_TEXTURE0 + index);
556    //glEnable(GL_TEXTURE_2D);
[1773]557    glBindTexture(GL_TEXTURE_2D, (int)tex.m_flags);
[1452]558    SetUniform(uni, index);
559#else
560    /* FIXME: unimplemented */
561#endif
562}
563
[2288]564/*
565 * Uniform setters for arrays
566 */
567
568void Shader::SetUniform(ShaderUniform const &uni, Array<float> const &v)
569{
570#if defined USE_D3D9 || defined _XBOX
571    /* FIXME: this will not work properly because we don't know how tell DX9
572     * it's a bunch of floats instead of vec4. */
573    if (uni.flags & 1)
574        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag,
575                                             &v[0], v.Count() / 4);
576    if (uni.flags & 2)
577        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert,
578                                              &v[0], v.Count() / 4);
579#elif !defined __CELLOS_LV2__
580    glUniform1fv(uni.frag, v.Count(), &v[0]);
581#else
582    if (uni.frag)
[2291]583        cgGLSetParameterArray1f((CGparameter)uni.frag,
584                                0, v.Count(), &v[0]);
[2288]585    if (uni.vert)
[2291]586        cgGLSetParameterArray1f((CGparameter)uni.vert,
587                                0, v.Count(), &v[0]);
[2288]588#endif
589}
590
591void Shader::SetUniform(ShaderUniform const &uni, Array<vec2> const &v)
592{
593#if defined USE_D3D9 || defined _XBOX
594    /* FIXME: this will not work properly because we don't know how tell DX9
595     * it's a bunch of vec2 instead of vec4. */
596    if (uni.flags & 1)
597        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag,
598                                             &v[0][0], v.Count() / 2);
599    if (uni.flags & 2)
600        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert,
601                                              &v[0][0], v.Count() / 2);
602#elif !defined __CELLOS_LV2__
603    glUniform2fv(uni.frag, v.Count(), &v[0][0]);
604#else
605    if (uni.frag)
[2291]606        cgGLSetParameterArray2f((CGparameter)uni.frag,
607                                0, v.Count(), &v[0][0]);
[2288]608    if (uni.vert)
[2291]609        cgGLSetParameterArray2f((CGparameter)uni.vert,
610                                0, v.Count(), &v[0][0]);
[2288]611#endif
612}
613
614void Shader::SetUniform(ShaderUniform const &uni, Array<vec3> const &v)
615{
616#if defined USE_D3D9 || defined _XBOX
617    /* FIXME: this will not work properly because we don't know how tell DX9
618     * it's a bunch of vec3 instead of vec4. */
619    if (uni.flags & 1)
620        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag,
621                                             &v[0][0], v.Count());
622    if (uni.flags & 2)
623        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert,
624                                              &v[0][0], v.Count());
625#elif !defined __CELLOS_LV2__
626    glUniform3fv(uni.frag, v.Count(), &v[0][0]);
627#else
628    if (uni.frag)
[2291]629        cgGLSetParameterArray3f((CGparameter)uni.frag,
630                                0, v.Count(), &v[0][0]);
[2288]631    if (uni.vert)
[2291]632        cgGLSetParameterArray3f((CGparameter)uni.vert,
633                                0, v.Count(), &v[0][0]);
[2288]634#endif
635}
636
637void Shader::SetUniform(ShaderUniform const &uni, Array<vec4> const &v)
638{
639#if defined USE_D3D9 || defined _XBOX
640    if (uni.flags & 1)
641        g_d3ddevice->SetPixelShaderConstantF((UINT)uni.frag,
642                                             &v[0][0], v.Count());
643    if (uni.flags & 2)
644        g_d3ddevice->SetVertexShaderConstantF((UINT)uni.vert,
645                                              &v[0][0], v.Count());
646#elif !defined __CELLOS_LV2__
647    glUniform4fv(uni.frag, v.Count(), &v[0][0]);
648#else
649    if (uni.frag)
[2291]650        cgGLSetParameterArray4f((CGparameter)uni.frag,
651                                0, v.Count(), &v[0][0]);
[2288]652    if (uni.vert)
[2291]653        cgGLSetParameterArray4f((CGparameter)uni.vert,
654                                0, v.Count(), &v[0][0]);
[2288]655#endif
656}
657
[659]658void Shader::Bind() const
659{
[1208]660#if defined USE_D3D9 || defined _XBOX
661    HRESULT hr;
662    hr = g_d3ddevice->SetVertexShader(data->vert_shader);
663    hr = g_d3ddevice->SetPixelShader(data->frag_shader);
[1179]664#elif !defined __CELLOS_LV2__
[828]665    glUseProgram(data->prog_id);
[758]666#else
[828]667    cgGLEnableProfile(cgGLGetLatestProfile(CG_GL_VERTEX));
668    cgGLBindProgram(data->vert_id);
669    cgGLEnableProfile(cgGLGetLatestProfile(CG_GL_FRAGMENT));
670    cgGLBindProgram(data->frag_id);
[758]671#endif
[659]672}
673
[1241]674void Shader::Unbind() const
675{
676#if defined USE_D3D9 || defined _XBOX
677    HRESULT hr;
678    hr = g_d3ddevice->SetVertexShader(NULL);
679    hr = g_d3ddevice->SetPixelShader(NULL);
680#elif !defined __CELLOS_LV2__
681    /* FIXME: untested */
682    glUseProgram(0);
683#else
684    /* FIXME: untested */
685    cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_VERTEX));
686    cgGLDisableProfile(cgGLGetLatestProfile(CG_GL_FRAGMENT));
687#endif
688}
689
[659]690Shader::~Shader()
691{
[1208]692#if defined USE_D3D9 || defined _XBOX
[1179]693    data->vert_shader->Release();
694    data->vert_table->Release();
695    data->frag_shader->Release();
696    data->frag_table->Release();
697#elif !defined __CELLOS_LV2__
[659]698    glDetachShader(data->prog_id, data->vert_id);
699    glDetachShader(data->prog_id, data->frag_id);
700    glDeleteShader(data->vert_id);
701    glDeleteShader(data->frag_id);
702    glDeleteProgram(data->prog_id);
[828]703#else
704    cgDestroyProgram(data->vert_id);
705    cgDestroyProgram(data->frag_id);
706#endif
[659]707    delete data;
708}
709
[775]710/* Try to detect shader compiler features */
711int ShaderData::GetVersion()
712{
713    static int version = 0;
714
[1208]715#if !defined USE_D3D9 && !defined _XBOX && !defined __CELLOS_LV2__
[775]716    if (!version)
717    {
[1690]718#if defined HAVE_GLES_2X
719        /* GLES 2.x supports #version 100, that's all. */
720        return 100;
721#else
[775]722        char buf[4096];
723        GLsizei len;
724
725        int id = glCreateShader(GL_VERTEX_SHADER);
726
727        /* Can we compile 1.30 shaders? */
728        char const *test130 =
729            "#version 130\n"
730            "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
731        glShaderSource(id, 1, &test130, NULL);
732        glCompileShader(id);
733        glGetShaderInfoLog(id, sizeof(buf), &len, buf);
734        if (len <= 0)
735            version = 130;
736
737        /* If not, can we compile 1.20 shaders? */
738        if (!version)
739        {
740            char const *test120 =
741                "#version 120\n"
742                "void main() { gl_Position = vec4(0.0, 0.0, 0.0, 0.0); }";
743            glShaderSource(id, 1, &test120, NULL);
744            glCompileShader(id);
745            glGetShaderInfoLog(id, sizeof(buf), &len, buf);
746            if (len <= 0)
747                version = 120;
748        }
749
750        /* Otherwise, assume we can compile 1.10 shaders. */
751        if (!version)
752            version = 110;
753
754        glDeleteShader(id);
[1690]755#endif
[775]756    }
[818]757#endif
[775]758
759    return version;
760}
761
762/* Simple shader source patching for old GLSL versions.
763 */
[778]764void ShaderData::Patch(char *dst, char const *vert, char const *frag)
[775]765{
[778]766    int ver_driver = GetVersion();
[775]767
[778]768    strcpy(dst, vert ? vert : frag);
769    if (ver_driver >= 130)
[775]770        return;
771
[778]772    int ver_shader = 110;
773    char *parser = strstr(dst, "#version");
774    if (parser)
775        ver_shader = atoi(parser + strlen("#version"));
776
[1690]777    /* This is GL ES, we only know version 100. */
778    if (ver_shader > 100 && ver_driver == 100)
779    {
780        /* FIXME: this isn't elegant but honestly, we don't care, this
781         * whole file is going to die soon. */
782        char *p = strstr(dst, "#version");
783        if (p)
784        {
785            p += 8;
786            while (*p == ' ')
787                p++;
788            if (p[0] == '1' && p[1] && p[2])
789                p[1] = p[2] = '0';
790        }
791    }
792
[778]793    if (ver_shader > 120 && ver_driver <= 120)
[775]794    {
[776]795        char const *end = dst + strlen(dst) + 1;
796
797        /* Find main() */
798        parser = strstr(dst, "main");
799        if (!parser) return;
800        parser = strstr(parser, "(");
801        if (!parser) return;
802        parser = strstr(parser, ")");
803        if (!parser) return;
804        parser = strstr(parser, "{");
805        if (!parser) return;
[778]806        char *main = parser + 1;
[776]807
808        /* Perform main() replaces */
[778]809        char const * const main_replaces[] =
[775]810        {
[778]811#if 0
[776]812            "in vec2 in_Vertex;", "vec2 in_Vertex = gl_Vertex.xy;",
813            "in vec3 in_Vertex;", "vec3 in_Vertex = gl_Vertex.xyz;",
814            "in vec4 in_Vertex;", "vec4 in_Vertex = gl_Vertex.xyzw;",
815
816            "in vec2 in_Color;", "vec2 in_Color = gl_Color.xy;",
817            "in vec3 in_Color;", "vec3 in_Color = gl_Color.xyz;",
818            "in vec4 in_Color;", "vec4 in_Color = gl_Color.xyzw;",
819
820            "in vec2 in_MultiTexCoord0;",
821               "vec2 in_MultiTexCoord0 = gl_MultiTexCoord0.xy;",
822            "in vec2 in_MultiTexCoord1;",
823               "vec2 in_MultiTexCoord1 = gl_MultiTexCoord1.xy;",
824            "in vec2 in_MultiTexCoord2;",
825               "vec2 in_MultiTexCoord2 = gl_MultiTexCoord2.xy;",
826            "in vec2 in_MultiTexCoord3;",
827               "vec2 in_MultiTexCoord3 = gl_MultiTexCoord3.xy;",
828            "in vec2 in_MultiTexCoord4;",
829               "vec2 in_MultiTexCoord4 = gl_MultiTexCoord4.xy;",
830            "in vec2 in_MultiTexCoord5;",
831               "vec2 in_MultiTexCoord5 = gl_MultiTexCoord5.xy;",
832            "in vec2 in_MultiTexCoord6;",
833               "vec2 in_MultiTexCoord6 = gl_MultiTexCoord6.xy;",
834            "in vec2 in_MultiTexCoord7;",
835               "vec2 in_MultiTexCoord7 = gl_MultiTexCoord7.xy;",
[778]836#endif
[776]837
[775]838            NULL
839        };
840
[776]841        for (char const * const *rep = main_replaces; rep[0]; rep += 2)
[775]842        {
[776]843            char *match = strstr(dst, rep[0]);
844            if (match && match < main)
[775]845            {
846                size_t l0 = strlen(rep[0]);
[776]847                size_t l1 = strlen(rep[1]);
848                memmove(main + l1, main, end - main);
849                memcpy(main, rep[1], l1);
850                memset(match, ' ', l0);
851                main += l1;
852                end += l1;
[775]853            }
[776]854        }
[775]855
[776]856        /* Perform small replaces */
[778]857        char const * const fast_replaces[] =
[776]858        {
859            "#version 130", "#version 120",
[778]860            "in vec2", vert ? "attribute vec2" : "varying vec2",
861            "in vec3", vert ? "attribute vec3" : "varying vec3",
862            "in vec4", vert ? "attribute vec4" : "varying vec4",
863            "in mat4", vert ? "attribute mat4" : "varying mat4",
864            "out vec2", "varying vec2",
865            "out vec3", "varying vec3",
866            "out vec4", "varying vec4",
867            "out mat4", "varying mat4",
[776]868            NULL
869        };
[775]870
[776]871        for (char const * const *rep = fast_replaces; rep[0]; rep += 2)
872        {
873            char *match;
874            while ((match = strstr(dst, rep[0])))
875            {
876                size_t l0 = strlen(rep[0]);
877                size_t l1 = strlen(rep[1]);
878
879                if (l1 > l0)
880                    memmove(match + l1, match + l0, (end - match) - l0);
881                memcpy(match, rep[1], l1);
882                if (l1 < l0)
883                    memset(match + l0, ' ', l1 - l0);
884                end += l1 - l0;
885            }
[775]886        }
887    }
888}
889
[686]890} /* namespace lol */
891
Note: See TracBrowser for help on using the repository browser.