eb179d4b67
*** WARNING: THIS COMMIT CHANGES THE BUILD *** Do not recurse into the backend directories to build private, internal libraries. We only recurse from clutter/ into the cogl sub-directory; from there, we don't recurse any further. All the backend-specific code in Cogl and Clutter is compiled conditionally depending on the macros defined by the configure script. We still recurse from the top-level directory into doc, clutter and tests, because gtk-doc and tests do not deal nicely with non-recursive layouts. This change makes Clutter compile slightly faster, and cleans up the build system, especially when dealing with introspection data. Ideally, we also want to make Cogl part of the top-level build, so that we can finally drop the sed trick to change the shared library from the GIR before compiling it. Currently disabled: ‣ OSX backend ‣ Fruity backend Currently enabled but untested: ‣ EGL backend ‣ Windows backend
489 lines
14 KiB
C
489 lines
14 KiB
C
/*
|
|
* Cogl
|
|
*
|
|
* An object oriented GL/GLES Abstraction/Utility Layer
|
|
*
|
|
* Copyright (C) 2008,2009,2010 Intel Corporation.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*
|
|
*
|
|
* Authors:
|
|
* Robert Bragg <robert@linux.intel.com>
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "cogl.h"
|
|
#include "cogl-program-gl.h"
|
|
#include "cogl-shader-private.h"
|
|
#include "cogl-internal.h"
|
|
#include "cogl-handle.h"
|
|
#include "cogl-context.h"
|
|
#include "cogl-journal-private.h"
|
|
#include "cogl-material-opengl-private.h"
|
|
|
|
#include <glib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#define glCreateProgram ctx->drv.pf_glCreateProgram
|
|
#define glAttachShader ctx->drv.pf_glAttachShader
|
|
#define glUseProgram ctx->drv.pf_glUseProgram
|
|
#define glLinkProgram ctx->drv.pf_glLinkProgram
|
|
#define glGetUniformLocation ctx->drv.pf_glGetUniformLocation
|
|
#define glUniform1f ctx->drv.pf_glUniform1f
|
|
#define glUniform2f ctx->drv.pf_glUniform2f
|
|
#define glUniform3f ctx->drv.pf_glUniform3f
|
|
#define glUniform4f ctx->drv.pf_glUniform4f
|
|
#define glUniform1fv ctx->drv.pf_glUniform1fv
|
|
#define glUniform2fv ctx->drv.pf_glUniform2fv
|
|
#define glUniform3fv ctx->drv.pf_glUniform3fv
|
|
#define glUniform4fv ctx->drv.pf_glUniform4fv
|
|
#define glUniform1i ctx->drv.pf_glUniform1i
|
|
#define glUniform2i ctx->drv.pf_glUniform2i
|
|
#define glUniform3i ctx->drv.pf_glUniform3i
|
|
#define glUniform4i ctx->drv.pf_glUniform4i
|
|
#define glUniform1iv ctx->drv.pf_glUniform1iv
|
|
#define glUniform2iv ctx->drv.pf_glUniform2iv
|
|
#define glUniform3iv ctx->drv.pf_glUniform3iv
|
|
#define glUniform4iv ctx->drv.pf_glUniform4iv
|
|
#define glUniformMatrix2fv ctx->drv.pf_glUniformMatrix2fv
|
|
#define glUniformMatrix3fv ctx->drv.pf_glUniformMatrix3fv
|
|
#define glUniformMatrix4fv ctx->drv.pf_glUniformMatrix4fv
|
|
#define glDeleteProgram ctx->drv.pf_glDeleteProgram
|
|
|
|
#define glProgramString ctx->drv.pf_glProgramString
|
|
#define glBindProgram ctx->drv.pf_glBindProgram
|
|
#define glDeletePrograms ctx->drv.pf_glDeletePrograms
|
|
#define glGenPrograms ctx->drv.pf_glGenPrograms
|
|
#define glProgramLocalParameter4fv ctx->drv.pf_glProgramLocalParameter4fv
|
|
|
|
|
|
static void _cogl_program_free (CoglProgram *program);
|
|
|
|
COGL_HANDLE_DEFINE (Program, program);
|
|
COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING (program);
|
|
|
|
static void
|
|
_cogl_program_free (CoglProgram *program)
|
|
{
|
|
/* Frees program resources but its handle is not
|
|
released! Do that separately before this! */
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
if (program->gl_handle)
|
|
{
|
|
if (program->language == COGL_SHADER_LANGUAGE_ARBFP)
|
|
GE (glDeletePrograms (1, &program->gl_handle));
|
|
else
|
|
GE (glDeleteProgram (program->gl_handle));
|
|
}
|
|
|
|
g_slice_free (CoglProgram, program);
|
|
}
|
|
|
|
CoglHandle
|
|
cogl_create_program (void)
|
|
{
|
|
CoglProgram *program;
|
|
_COGL_GET_CONTEXT (ctx, NULL);
|
|
|
|
program = g_slice_new0 (CoglProgram);
|
|
|
|
return _cogl_program_handle_new (program);
|
|
}
|
|
|
|
void
|
|
cogl_program_attach_shader (CoglHandle program_handle,
|
|
CoglHandle shader_handle)
|
|
{
|
|
CoglProgram *program;
|
|
CoglShader *shader;
|
|
CoglShaderLanguage language;
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
g_return_if_fail (cogl_is_program (program_handle));
|
|
g_return_if_fail (cogl_is_shader (shader_handle));
|
|
|
|
program = _cogl_program_pointer_from_handle (program_handle);
|
|
shader = _cogl_shader_pointer_from_handle (shader_handle);
|
|
|
|
language = shader->language;
|
|
|
|
/* We only allow attaching one ARBfp shader to a program */
|
|
if (language == COGL_SHADER_LANGUAGE_ARBFP)
|
|
g_return_if_fail (program->gl_handle == 0);
|
|
|
|
program->language = language;
|
|
|
|
if (language == COGL_SHADER_LANGUAGE_ARBFP)
|
|
{
|
|
#ifdef COGL_GL_DEBUG
|
|
GLenum gl_error;
|
|
#endif
|
|
|
|
GE (glGenPrograms (1, &program->gl_handle));
|
|
|
|
GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, program->gl_handle));
|
|
|
|
#ifdef COGL_GL_DEBUG
|
|
while ((gl_error = glGetError ()) != GL_NO_ERROR)
|
|
;
|
|
#endif
|
|
glProgramString (GL_FRAGMENT_PROGRAM_ARB,
|
|
GL_PROGRAM_FORMAT_ASCII_ARB,
|
|
strlen (shader->arbfp_source),
|
|
shader->arbfp_source);
|
|
#ifdef COGL_GL_DEBUG
|
|
gl_error = glGetError ();
|
|
if (gl_error != GL_NO_ERROR)
|
|
{
|
|
g_warning ("%s: GL error (%d): Failed to compile ARBfp:\n%s\n%s",
|
|
G_STRLOC,
|
|
gl_error,
|
|
shader->arbfp_source,
|
|
glGetString (GL_PROGRAM_ERROR_STRING_ARB));
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if (!program->gl_handle)
|
|
program->gl_handle = glCreateProgram ();
|
|
GE (glAttachShader (program->gl_handle, shader->gl_handle));
|
|
}
|
|
|
|
/* NB: There is no separation between shader objects and program
|
|
* objects for ARBfp */
|
|
}
|
|
|
|
void
|
|
cogl_program_link (CoglHandle handle)
|
|
{
|
|
CoglProgram *program;
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
if (!cogl_is_program (handle))
|
|
return;
|
|
|
|
program = _cogl_program_pointer_from_handle (handle);
|
|
|
|
if (program->language == COGL_SHADER_LANGUAGE_GLSL &&
|
|
program->gl_handle)
|
|
GE (glLinkProgram (program->gl_handle));
|
|
|
|
program->is_linked = TRUE;
|
|
}
|
|
|
|
void
|
|
cogl_program_use (CoglHandle handle)
|
|
{
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
g_return_if_fail (handle == COGL_INVALID_HANDLE ||
|
|
cogl_is_program (handle));
|
|
|
|
if (handle != COGL_INVALID_HANDLE)
|
|
{
|
|
CoglProgram *program = handle;
|
|
g_return_if_fail (program->is_linked);
|
|
}
|
|
|
|
if (ctx->current_program == 0 && handle != 0)
|
|
ctx->legacy_state_set++;
|
|
else if (handle == 0 && ctx->current_program != 0)
|
|
ctx->legacy_state_set--;
|
|
|
|
if (handle != COGL_INVALID_HANDLE)
|
|
cogl_handle_ref (handle);
|
|
if (ctx->current_program != COGL_INVALID_HANDLE)
|
|
cogl_handle_unref (ctx->current_program);
|
|
ctx->current_program = handle;
|
|
}
|
|
|
|
/* ARBfp local parameters can be referenced like:
|
|
*
|
|
* "program.local[5]"
|
|
* ^14char offset (after whitespace is stripped)
|
|
*/
|
|
static int
|
|
get_local_param_index (const char *uniform_name)
|
|
{
|
|
char *input = g_strdup (uniform_name);
|
|
int i;
|
|
char *p = input;
|
|
char *endptr;
|
|
int _index;
|
|
|
|
for (i = 0; input[i] != '\0'; i++)
|
|
if (input[i] != '_' && input[i] != '\t')
|
|
*p++ = input[i];
|
|
input[i] = '\0';
|
|
|
|
g_return_val_if_fail (strncmp ("program.local[", input, 14) == 0, -1);
|
|
|
|
_index = g_ascii_strtoull (input + 14, &endptr, 10);
|
|
g_return_val_if_fail (endptr != input + 14, -1);
|
|
g_return_val_if_fail (*endptr == ']', -1);
|
|
|
|
g_return_val_if_fail (_index >= 0 &&
|
|
_index < COGL_PROGRAM_MAX_ARBFP_LOCAL_PARAMS, -1);
|
|
|
|
g_free (input);
|
|
|
|
return _index;
|
|
}
|
|
|
|
int
|
|
cogl_program_get_uniform_location (CoglHandle handle,
|
|
const char *uniform_name)
|
|
{
|
|
CoglProgram *program;
|
|
_COGL_GET_CONTEXT (ctx, 0);
|
|
|
|
if (!cogl_is_program (handle))
|
|
return 0;
|
|
|
|
program = _cogl_program_pointer_from_handle (handle);
|
|
|
|
if (program->language == COGL_SHADER_LANGUAGE_ARBFP)
|
|
return get_local_param_index (uniform_name);
|
|
else
|
|
return glGetUniformLocation (program->gl_handle, uniform_name);
|
|
}
|
|
|
|
void
|
|
cogl_program_set_uniform_1f (CoglHandle handle,
|
|
int uniform_location,
|
|
float value)
|
|
{
|
|
CoglProgram *program = handle;
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
g_return_if_fail (cogl_is_program (handle));
|
|
g_return_if_fail (program->language != COGL_SHADER_LANGUAGE_ARBFP);
|
|
|
|
_cogl_gl_use_program_wrapper (program);
|
|
|
|
GE (glUniform1f (uniform_location, value));
|
|
}
|
|
|
|
void
|
|
cogl_program_uniform_1f (int uniform_location,
|
|
float value)
|
|
{
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
cogl_program_set_uniform_1f (ctx->current_program,
|
|
uniform_location, value);
|
|
}
|
|
|
|
void
|
|
cogl_program_set_uniform_1i (CoglHandle handle,
|
|
int uniform_location,
|
|
int value)
|
|
{
|
|
CoglProgram *program = handle;
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
g_return_if_fail (cogl_is_program (handle));
|
|
g_return_if_fail (program->language != COGL_SHADER_LANGUAGE_ARBFP);
|
|
|
|
_cogl_gl_use_program_wrapper (program);
|
|
|
|
GE (glUniform1i (uniform_location, value));
|
|
}
|
|
|
|
void
|
|
cogl_program_uniform_1i (int uniform_location,
|
|
int value)
|
|
{
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
cogl_program_set_uniform_1i (ctx->current_program, uniform_location, value);
|
|
}
|
|
|
|
void
|
|
cogl_program_set_uniform_float (CoglHandle handle,
|
|
int uniform_location,
|
|
int n_components,
|
|
int count,
|
|
const float *value)
|
|
{
|
|
CoglProgram *program = handle;
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
g_return_if_fail (cogl_is_program (handle));
|
|
|
|
if (program->language == COGL_SHADER_LANGUAGE_ARBFP)
|
|
{
|
|
unsigned int _index = uniform_location;
|
|
unsigned int index_end = _index + count;
|
|
int i;
|
|
int j;
|
|
|
|
g_return_if_fail (n_components == 4);
|
|
|
|
GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, program->gl_handle));
|
|
|
|
for (i = _index; i < index_end; i++)
|
|
for (j = 0; j < 4; j++)
|
|
program->arbfp_local_params[i][j] = *(value++);
|
|
|
|
for (i = _index; i < index_end; i++)
|
|
GE (glProgramLocalParameter4fv (GL_FRAGMENT_PROGRAM_ARB,
|
|
i,
|
|
&program->arbfp_local_params[i][0]));
|
|
}
|
|
else
|
|
{
|
|
_cogl_gl_use_program_wrapper (program);
|
|
|
|
switch (n_components)
|
|
{
|
|
case 1:
|
|
GE (glUniform1fv (uniform_location, count, value));
|
|
break;
|
|
case 2:
|
|
GE (glUniform2fv (uniform_location, count, value));
|
|
break;
|
|
case 3:
|
|
GE (glUniform3fv (uniform_location, count, value));
|
|
break;
|
|
case 4:
|
|
GE (glUniform4fv (uniform_location, count, value));
|
|
break;
|
|
default:
|
|
g_warning ("%s called with invalid size parameter", G_STRFUNC);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
cogl_program_uniform_float (int uniform_location,
|
|
int n_components,
|
|
int count,
|
|
const float *value)
|
|
{
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
cogl_program_set_uniform_float (ctx->current_program,
|
|
uniform_location,
|
|
n_components, count, value);
|
|
}
|
|
|
|
void
|
|
cogl_program_set_uniform_int (CoglHandle handle,
|
|
int uniform_location,
|
|
int n_components,
|
|
int count,
|
|
const int *value)
|
|
{
|
|
CoglProgram *program = handle;
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
g_return_if_fail (cogl_is_program (handle));
|
|
|
|
_cogl_gl_use_program_wrapper (program);
|
|
|
|
switch (n_components)
|
|
{
|
|
case 1:
|
|
glUniform1iv (uniform_location, count, value);
|
|
break;
|
|
case 2:
|
|
glUniform2iv (uniform_location, count, value);
|
|
break;
|
|
case 3:
|
|
glUniform3iv (uniform_location, count, value);
|
|
break;
|
|
case 4:
|
|
glUniform4iv (uniform_location, count, value);
|
|
break;
|
|
default:
|
|
g_warning ("%s called with invalid size parameter", G_STRFUNC);
|
|
}
|
|
}
|
|
|
|
void
|
|
cogl_program_uniform_int (int uniform_location,
|
|
int n_components,
|
|
int count,
|
|
const int *value)
|
|
{
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
cogl_program_set_uniform_int (ctx->current_program,
|
|
uniform_location, n_components, count, value);
|
|
}
|
|
|
|
void
|
|
cogl_program_set_uniform_matrix (CoglHandle handle,
|
|
int uniform_location,
|
|
int n_components,
|
|
int count,
|
|
gboolean transpose,
|
|
const float*value)
|
|
{
|
|
CoglProgram *program = handle;
|
|
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
|
|
g_return_if_fail (cogl_is_program (handle));
|
|
g_return_if_fail (program->language != COGL_SHADER_LANGUAGE_ARBFP);
|
|
|
|
_cogl_gl_use_program_wrapper (program);
|
|
|
|
switch (n_components)
|
|
{
|
|
case 2 :
|
|
GE (glUniformMatrix2fv (uniform_location, count, transpose, value));
|
|
break;
|
|
case 3 :
|
|
GE (glUniformMatrix3fv (uniform_location, count, transpose, value));
|
|
break;
|
|
case 4 :
|
|
GE (glUniformMatrix4fv (uniform_location, count, transpose, value));
|
|
break;
|
|
default :
|
|
g_warning ("%s called with invalid size parameter", G_STRFUNC);
|
|
}
|
|
}
|
|
|
|
void
|
|
cogl_program_uniform_matrix (int uniform_location,
|
|
int dimensions,
|
|
int count,
|
|
gboolean transpose,
|
|
const float *value)
|
|
{
|
|
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
|
cogl_program_set_uniform_matrix (ctx->current_program,
|
|
uniform_location, dimensions,
|
|
count, transpose, value);
|
|
}
|
|
|
|
CoglShaderLanguage
|
|
_cogl_program_get_language (CoglHandle handle)
|
|
{
|
|
CoglProgram *program = handle;
|
|
return program->language;
|
|
}
|
|
|