cogl: Allow setting ARBfp source on a CoglShader

This makes CoglProgram/Shader automatically detect when the user has
given an ARBfp program by checking for "!!ARBfp1.0" at the beginning of
the user's source.

ARBfp local parameters can be set with cogl_program_uniform_float
assuming you pass a @size of 4 (all ARBfp program.local parameters
are vectors of 4 floats).

This doesn't expose ARBfp environment parameters or double precision
local parameters.
This commit is contained in:
Robert Bragg 2010-08-04 17:53:51 +01:00
parent 5741e28cdc
commit 09e664c349
8 changed files with 373 additions and 84 deletions

View File

@ -79,6 +79,7 @@ typedef struct _CoglMaterialBackendARBfpPrivate
CoglMaterial *authority_cache; CoglMaterial *authority_cache;
unsigned long authority_cache_age; unsigned long authority_cache_age;
CoglHandle user_program;
GString *source; GString *source;
GLuint gl_program; GLuint gl_program;
gboolean *sampled; gboolean *sampled;
@ -160,7 +161,7 @@ layers_arbfp_would_differ (CoglMaterialLayer **material0_layers,
* generate. * generate.
*/ */
static CoglMaterial * static CoglMaterial *
find_arbfp_authority (CoglMaterial *material) find_arbfp_authority (CoglMaterial *material, CoglHandle user_program)
{ {
CoglMaterial *authority0; CoglMaterial *authority0;
CoglMaterial *authority1; CoglMaterial *authority1;
@ -171,6 +172,9 @@ find_arbfp_authority (CoglMaterial *material)
/* XXX: we'll need to update this when we add fog support to the /* XXX: we'll need to update this when we add fog support to the
* arbfp codegen */ * arbfp codegen */
if (user_program != COGL_INVALID_HANDLE)
return material;
/* Find the first material that modifies state that affects the /* Find the first material that modifies state that affects the
* arbfp codegen... */ * arbfp codegen... */
authority0 = _cogl_material_get_authority (material, authority0 = _cogl_material_get_authority (material,
@ -253,9 +257,13 @@ _cogl_material_backend_arbfp_start (CoglMaterial *material,
CoglMaterial *authority; CoglMaterial *authority;
CoglMaterialBackendARBfpPrivate *priv; CoglMaterialBackendARBfpPrivate *priv;
CoglMaterialBackendARBfpPrivate *authority_priv; CoglMaterialBackendARBfpPrivate *authority_priv;
CoglHandle user_program;
_COGL_GET_CONTEXT (ctx, FALSE); _COGL_GET_CONTEXT (ctx, FALSE);
/* First validate that we can handle the current state using ARBfp
*/
if (!cogl_features_available (COGL_FEATURE_SHADERS_ARBFP)) if (!cogl_features_available (COGL_FEATURE_SHADERS_ARBFP))
return FALSE; return FALSE;
@ -263,11 +271,23 @@ _cogl_material_backend_arbfp_start (CoglMaterial *material,
if (ctx->legacy_fog_state.enabled) if (ctx->legacy_fog_state.enabled)
return FALSE; return FALSE;
user_program = cogl_material_get_user_program (material);
if (user_program != COGL_INVALID_HANDLE &&
_cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_ARBFP)
return FALSE;
/* Now lookup our ARBfp backend private state (allocating if
* necessary) that may contain a cache pointer refering us to the
* material's "arbfp-authority".
*
* The arbfp-authority is the oldest ancestor whos state will result in
* the same program being generated.
*/
/* Note: we allocate ARBfp private state for both the given material /* Note: we allocate ARBfp private state for both the given material
* and the authority. (The oldest ancestor whos state will result in * and the arbfp-authority. The former will simply cache a pointer
* the same program being generated) The former will simply cache a * to the authority and the later will track the arbfp program that
* pointer to the authority and the later will track the arbfp * we will generate.
* program that we will generate.
*/ */
if (!(material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK)) if (!(material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK))
@ -285,16 +305,24 @@ _cogl_material_backend_arbfp_start (CoglMaterial *material,
* may invalidate authority_cache pointers. * may invalidate authority_cache pointers.
*/ */
/* If the given material has changed since we last cached its
* arbfp-authority then invalidate our cache and then search the
* material's ancestors for one with matching fragment processing
* state. */
if (priv->authority_cache && if (priv->authority_cache &&
priv->authority_cache_age != _cogl_material_get_age (material)) priv->authority_cache_age != _cogl_material_get_age (material))
invalidate_arbfp_authority_cache (material); invalidate_arbfp_authority_cache (material);
if (!priv->authority_cache) if (!priv->authority_cache)
{ {
priv->authority_cache = find_arbfp_authority (material); priv->authority_cache = find_arbfp_authority (material, user_program);
priv->authority_cache_age = _cogl_material_get_age (material); priv->authority_cache_age = _cogl_material_get_age (material);
} }
/* Now we have our arbfp-authority fetch the ARBfp backend private
* state from it (allocting if necessary) */
authority = priv->authority_cache; authority = priv->authority_cache;
if (!(authority->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK)) if (!(authority->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK))
{ {
@ -304,7 +332,9 @@ _cogl_material_backend_arbfp_start (CoglMaterial *material,
} }
authority_priv = authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP]; authority_priv = authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
if (authority_priv->gl_program == 0) authority_priv->user_program = user_program;
if (user_program == COGL_INVALID_HANDLE && authority_priv->gl_program == 0)
{ {
/* We reuse a single grow-only GString for ARBfp code-gen */ /* We reuse a single grow-only GString for ARBfp code-gen */
g_string_set_size (ctx->arbfp_source_buffer, 0); g_string_set_size (ctx->arbfp_source_buffer, 0);
@ -912,6 +942,7 @@ _cogl_material_backend_arbfp_end (CoglMaterial *material,
CoglMaterial *arbfp_authority = get_arbfp_authority (material); CoglMaterial *arbfp_authority = get_arbfp_authority (material);
CoglMaterialBackendARBfpPrivate *priv = CoglMaterialBackendARBfpPrivate *priv =
arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP]; arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
GLuint gl_program;
_COGL_GET_CONTEXT (ctx, FALSE); _COGL_GET_CONTEXT (ctx, FALSE);
@ -954,9 +985,16 @@ _cogl_material_backend_arbfp_end (CoglMaterial *material,
g_free (priv->sampled); g_free (priv->sampled);
priv->sampled = NULL; priv->sampled = NULL;
} }
else
GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, priv->gl_program));
if (priv->user_program != COGL_INVALID_HANDLE)
{
CoglProgram *program = (CoglProgram *)priv->user_program;
gl_program = program->gl_handle;
}
else
gl_program = priv->gl_program;
GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, gl_program));
_cogl_use_program (COGL_INVALID_HANDLE, COGL_MATERIAL_PROGRAM_TYPE_ARBFP); _cogl_use_program (COGL_INVALID_HANDLE, COGL_MATERIAL_PROGRAM_TYPE_ARBFP);
return TRUE; return TRUE;
@ -968,17 +1006,23 @@ _cogl_material_backend_arbfp_material_pre_change_notify (
CoglMaterialState change, CoglMaterialState change,
const CoglColor *new_color) const CoglColor *new_color)
{ {
CoglMaterialBackendARBfpPrivate *priv = CoglMaterialBackendARBfpPrivate *priv;
material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
static const unsigned long fragment_op_changes = static const unsigned long fragment_op_changes =
COGL_MATERIAL_STATE_LAYERS; COGL_MATERIAL_STATE_LAYERS |
COGL_MATERIAL_STATE_USER_SHADER;
/* TODO: COGL_MATERIAL_STATE_FOG */ /* TODO: COGL_MATERIAL_STATE_FOG */
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK && if (!(material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK) ||
priv->gl_program && !(change & fragment_op_changes))
change & fragment_op_changes) return;
priv = material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
priv->user_program = COGL_INVALID_HANDLE;
if (priv->gl_program)
{ {
GE (glDeletePrograms (1, &priv->gl_program)); GE (glDeletePrograms (1, &priv->gl_program));
priv->gl_program = 0; priv->gl_program = 0;

View File

@ -63,28 +63,20 @@ _cogl_material_backend_glsl_start (CoglMaterial *material,
int n_layers, int n_layers,
unsigned long materials_difference) unsigned long materials_difference)
{ {
CoglHandle program;
_COGL_GET_CONTEXT (ctx, FALSE); _COGL_GET_CONTEXT (ctx, FALSE);
if (!cogl_features_available (COGL_FEATURE_SHADERS_GLSL)) if (!cogl_features_available (COGL_FEATURE_SHADERS_GLSL))
return FALSE; return FALSE;
if (materials_difference & COGL_MATERIAL_STATE_USER_SHADER) program = cogl_material_get_user_program (material);
{ if (program == COGL_INVALID_HANDLE ||
CoglMaterial *authority = _cogl_program_get_language (program) != COGL_SHADER_LANGUAGE_GLSL)
_cogl_material_get_authority (material, return FALSE; /* XXX: change me when we support code generation here */
COGL_MATERIAL_STATE_USER_SHADER);
CoglHandle program = authority->big_state->user_program;
if (program == COGL_INVALID_HANDLE) _cogl_use_program (program, COGL_MATERIAL_PROGRAM_TYPE_GLSL);
return FALSE; /* XXX: change me when we support code generation here */ return TRUE;
_cogl_use_program (program, COGL_MATERIAL_PROGRAM_TYPE_GLSL);
return TRUE;
}
/* TODO: also support code generation */
return FALSE;
} }
gboolean gboolean

View File

@ -28,13 +28,26 @@
typedef struct _CoglShader CoglShader; typedef struct _CoglShader CoglShader;
typedef enum
{
COGL_SHADER_LANGUAGE_GLSL,
#ifdef HAVE_COGL_GL
COGL_SHADER_LANGUAGE_ARBFP
#endif
} CoglShaderLanguage;
struct _CoglShader struct _CoglShader
{ {
CoglHandleObject _parent; CoglHandleObject _parent;
GLuint gl_handle; GLuint gl_handle;
char *arbfp_source;
CoglShaderType type; CoglShaderType type;
CoglShaderLanguage language;
}; };
CoglShader *_cogl_shader_pointer_from_handle (CoglHandle handle); CoglShader *_cogl_shader_pointer_from_handle (CoglHandle handle);
CoglShaderLanguage
_cogl_program_get_language (CoglHandle handle);
#endif /* __COGL_SHADER_H */ #endif /* __COGL_SHADER_H */

View File

@ -33,6 +33,8 @@
#include <glib.h> #include <glib.h>
#include <string.h>
#ifdef HAVE_COGL_GL #ifdef HAVE_COGL_GL
#define glCreateShader ctx->drv.pf_glCreateShader #define glCreateShader ctx->drv.pf_glCreateShader
#define glGetShaderiv ctx->drv.pf_glGetShaderiv #define glGetShaderiv ctx->drv.pf_glGetShaderiv
@ -58,7 +60,14 @@ _cogl_shader_free (CoglShader *shader)
/* Frees shader resources but its handle is not /* Frees shader resources but its handle is not
released! Do that separately before this! */ released! Do that separately before this! */
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
glDeleteShader (shader->gl_handle);
#ifdef HAVE_COGL_GL
if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
g_free (shader->arbfp_source);
else
#endif
if (shader->gl_handle)
GE (glDeleteShader (shader->gl_handle));
g_slice_free (CoglShader, shader); g_slice_free (CoglShader, shader);
} }
@ -67,23 +76,23 @@ CoglHandle
cogl_create_shader (CoglShaderType type) cogl_create_shader (CoglShaderType type)
{ {
CoglShader *shader; CoglShader *shader;
GLenum gl_type;
GET_CONTEXT (ctx, COGL_INVALID_HANDLE); GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
if (type == COGL_SHADER_TYPE_VERTEX) switch (type)
gl_type = GL_VERTEX_SHADER;
else if (type == COGL_SHADER_TYPE_FRAGMENT)
gl_type = GL_FRAGMENT_SHADER;
else
{ {
case COGL_SHADER_TYPE_VERTEX:
case COGL_SHADER_TYPE_FRAGMENT:
break;
default:
g_warning ("Unexpected shader type (0x%08lX) given to " g_warning ("Unexpected shader type (0x%08lX) given to "
"cogl_create_shader", (unsigned long) type); "cogl_create_shader", (unsigned long) type);
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
} }
shader = g_slice_new (CoglShader); shader = g_slice_new (CoglShader);
shader->gl_handle = glCreateShader (gl_type); shader->language = COGL_SHADER_LANGUAGE_GLSL;
shader->gl_handle = 0;
shader->type = type; shader->type = type;
return _cogl_shader_handle_new (shader); return _cogl_shader_handle_new (shader);
@ -94,6 +103,8 @@ cogl_shader_source (CoglHandle handle,
const char *source) const char *source)
{ {
CoglShader *shader; CoglShader *shader;
CoglShaderLanguage language;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!cogl_is_shader (handle)) if (!cogl_is_shader (handle))
@ -101,7 +112,57 @@ cogl_shader_source (CoglHandle handle,
shader = _cogl_shader_pointer_from_handle (handle); shader = _cogl_shader_pointer_from_handle (handle);
glShaderSource (shader->gl_handle, 1, &source, NULL); #ifdef HAVE_COGL_GL
if (strncmp (source, "!!ARBfp1.0", 10) == 0)
language = COGL_SHADER_LANGUAGE_ARBFP;
else
#endif
language = COGL_SHADER_LANGUAGE_GLSL;
/* Delete the old object if the language is changing... */
if (G_UNLIKELY (language != shader->language))
{
#ifdef HAVE_COGL_GL
if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
{
g_free (shader->arbfp_source);
shader->arbfp_source = NULL;
}
#endif
else
{
if (shader->gl_handle)
GE (glDeleteShader (shader->gl_handle));
}
}
#ifdef HAVE_COGL_GL
if (language == COGL_SHADER_LANGUAGE_ARBFP)
shader->arbfp_source = g_strdup (source);
else
#endif
{
if (!shader->gl_handle)
{
GLenum gl_type;
switch (shader->type)
{
case COGL_SHADER_TYPE_VERTEX:
gl_type = GL_VERTEX_SHADER;
break;
case COGL_SHADER_TYPE_FRAGMENT:
gl_type = GL_FRAGMENT_SHADER;
break;
}
shader->gl_handle = glCreateShader (gl_type);
}
glShaderSource (shader->gl_handle, 1, &source, NULL);
}
shader->language = language;
} }
void void
@ -115,15 +176,14 @@ cogl_shader_compile (CoglHandle handle)
shader = _cogl_shader_pointer_from_handle (handle); shader = _cogl_shader_pointer_from_handle (handle);
glCompileShader (shader->gl_handle); if (shader->language == COGL_SHADER_LANGUAGE_GLSL)
GE (glCompileShader (shader->gl_handle));
} }
char * char *
cogl_shader_get_info_log (CoglHandle handle) cogl_shader_get_info_log (CoglHandle handle)
{ {
CoglShader *shader; CoglShader *shader;
char buffer[512];
int len = 0;
GET_CONTEXT (ctx, NULL); GET_CONTEXT (ctx, NULL);
@ -132,10 +192,21 @@ cogl_shader_get_info_log (CoglHandle handle)
shader = _cogl_shader_pointer_from_handle (handle); shader = _cogl_shader_pointer_from_handle (handle);
glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer); if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
buffer[len] = '\0'; {
/* ARBfp exposes a program error string, but since cogl_program
return g_strdup (buffer); * doesn't have any API to query an error log it is not currently
* exposed. */
return "";
}
else
{
char buffer[512];
int len = 0;
glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer);
buffer[len] = '\0';
return g_strdup (buffer);
}
} }
CoglShaderType CoglShaderType
@ -168,11 +239,18 @@ cogl_shader_is_compiled (CoglHandle handle)
shader = _cogl_shader_pointer_from_handle (handle); shader = _cogl_shader_pointer_from_handle (handle);
GE (glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status)); #ifdef HAVE_COGL_GL
if (status == GL_TRUE) if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
return TRUE; return TRUE;
else else
return FALSE; #endif
{
GE (glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status));
if (status == GL_TRUE)
return TRUE;
else
return FALSE;
}
} }
#else /* HAVE_COGL_GLES */ #else /* HAVE_COGL_GLES */

View File

@ -496,6 +496,9 @@ cogl_get_features (void)
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_PBOS)) if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_PBOS))
ctx->feature_flags &= ~COGL_FEATURE_PBOS; ctx->feature_flags &= ~COGL_FEATURE_PBOS;
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_ARBFP))
ctx->feature_flags &= ~COGL_FEATURE_SHADERS_ARBFP;
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_GLSL)) if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_GLSL))
ctx->feature_flags &= ~COGL_FEATURE_SHADERS_GLSL; ctx->feature_flags &= ~COGL_FEATURE_SHADERS_GLSL;
@ -521,9 +524,6 @@ _cogl_features_available_private (CoglFeatureFlagsPrivate features)
if (!ctx->features_cached) if (!ctx->features_cached)
_cogl_features_init (); _cogl_features_init ();
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_ARBFP))
ctx->feature_flags_private &= ~COGL_FEATURE_SHADERS_ARBFP;
return (ctx->feature_flags_private & features) == features; return (ctx->feature_flags_private & features) == features;
} }

View File

@ -16,9 +16,12 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
* *
* *
* Authors:
* Robert Bragg <robert@linux.intel.com>
*/ */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -36,6 +39,8 @@
#include <glib.h> #include <glib.h>
#include <string.h>
#define glCreateProgram ctx->drv.pf_glCreateProgram #define glCreateProgram ctx->drv.pf_glCreateProgram
#define glAttachShader ctx->drv.pf_glAttachShader #define glAttachShader ctx->drv.pf_glAttachShader
#define glUseProgram ctx->drv.pf_glUseProgram #define glUseProgram ctx->drv.pf_glUseProgram
@ -62,6 +67,13 @@
#define glUniformMatrix4fv ctx->drv.pf_glUniformMatrix4fv #define glUniformMatrix4fv ctx->drv.pf_glUniformMatrix4fv
#define glDeleteProgram ctx->drv.pf_glDeleteProgram #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); static void _cogl_program_free (CoglProgram *program);
COGL_HANDLE_DEFINE (Program, program); COGL_HANDLE_DEFINE (Program, program);
@ -73,7 +85,14 @@ _cogl_program_free (CoglProgram *program)
/* Frees program resources but its handle is not /* Frees program resources but its handle is not
released! Do that separately before this! */ released! Do that separately before this! */
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
GE (glDeleteProgram (program->gl_handle));
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); g_slice_free (CoglProgram, program);
} }
@ -84,8 +103,7 @@ cogl_create_program (void)
CoglProgram *program; CoglProgram *program;
_COGL_GET_CONTEXT (ctx, NULL); _COGL_GET_CONTEXT (ctx, NULL);
program = g_slice_new (CoglProgram); program = g_slice_new0 (CoglProgram);
program->gl_handle = glCreateProgram ();
return _cogl_program_handle_new (program); return _cogl_program_handle_new (program);
} }
@ -96,16 +114,63 @@ cogl_program_attach_shader (CoglHandle program_handle,
{ {
CoglProgram *program; CoglProgram *program;
CoglShader *shader; CoglShader *shader;
CoglShaderLanguage language;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!cogl_is_program (program_handle) || !cogl_is_shader (shader_handle)) g_return_if_fail (cogl_is_program (program_handle));
return; g_return_if_fail (cogl_is_shader (shader_handle));
program = _cogl_program_pointer_from_handle (program_handle); program = _cogl_program_pointer_from_handle (program_handle);
shader = _cogl_shader_pointer_from_handle (shader_handle); shader = _cogl_shader_pointer_from_handle (shader_handle);
GE (glAttachShader (program->gl_handle, shader->gl_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 void
@ -119,7 +184,11 @@ cogl_program_link (CoglHandle handle)
program = _cogl_program_pointer_from_handle (handle); program = _cogl_program_pointer_from_handle (handle);
GE (glLinkProgram (program->gl_handle)); if (program->language == COGL_SHADER_LANGUAGE_GLSL &&
program->gl_handle)
GE (glLinkProgram (program->gl_handle));
program->is_linked = TRUE;
} }
void void
@ -130,6 +199,12 @@ cogl_program_use (CoglHandle handle)
g_return_if_fail (handle == COGL_INVALID_HANDLE || g_return_if_fail (handle == COGL_INVALID_HANDLE ||
cogl_is_program (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) if (ctx->current_program == 0 && handle != 0)
ctx->legacy_state_set++; ctx->legacy_state_set++;
else if (handle == 0 && ctx->current_program != 0) else if (handle == 0 && ctx->current_program != 0)
@ -142,6 +217,39 @@ cogl_program_use (CoglHandle handle)
ctx->current_program = handle; 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 int
cogl_program_get_uniform_location (CoglHandle handle, cogl_program_get_uniform_location (CoglHandle handle,
const char *uniform_name) const char *uniform_name)
@ -154,7 +262,10 @@ cogl_program_get_uniform_location (CoglHandle handle,
program = _cogl_program_pointer_from_handle (handle); program = _cogl_program_pointer_from_handle (handle);
return glGetUniformLocation (program->gl_handle, uniform_name); if (program->language == COGL_SHADER_LANGUAGE_ARBFP)
return get_local_param_index (uniform_name);
else
return glGetUniformLocation (program->gl_handle, uniform_name);
} }
void void
@ -169,6 +280,8 @@ cogl_program_uniform_1f (int uniform_no,
g_return_if_fail (program != NULL); g_return_if_fail (program != NULL);
g_return_if_fail (program->language != COGL_SHADER_LANGUAGE_ARBFP);
_cogl_gl_use_program_wrapper (program); _cogl_gl_use_program_wrapper (program);
GE (glUniform1f (uniform_no, value)); GE (glUniform1f (uniform_no, value));
@ -186,15 +299,17 @@ cogl_program_uniform_1i (int uniform_no,
g_return_if_fail (program != NULL); g_return_if_fail (program != NULL);
g_return_if_fail (program->language != COGL_SHADER_LANGUAGE_ARBFP);
_cogl_gl_use_program_wrapper (program); _cogl_gl_use_program_wrapper (program);
GE (glUniform1i (uniform_no, value)); GE (glUniform1i (uniform_no, value));
} }
void void
cogl_program_uniform_float (int uniform_no, cogl_program_uniform_float (int uniform_no,
int size, int size,
int count, int count,
const GLfloat *value) const GLfloat *value)
{ {
CoglProgram *program; CoglProgram *program;
@ -205,24 +320,47 @@ cogl_program_uniform_float (int uniform_no,
g_return_if_fail (program != NULL); g_return_if_fail (program != NULL);
_cogl_gl_use_program_wrapper (program); if (program->language == COGL_SHADER_LANGUAGE_ARBFP)
switch (size)
{ {
case 1: unsigned int _index = uniform_no;
GE (glUniform1fv (uniform_no, count, value)); unsigned int index_end = _index + count;
break; int i;
case 2: int j;
GE (glUniform2fv (uniform_no, count, value));
break; g_return_if_fail (size == 4);
case 3:
GE (glUniform3fv (uniform_no, count, value)); GE (glBindProgram (GL_FRAGMENT_PROGRAM_ARB, program->gl_handle));
break;
case 4: for (i = _index; i < index_end; i++)
GE (glUniform4fv (uniform_no, count, value)); for (j = 0; j < 4; j++)
break; program->arbfp_local_params[i][j] = *(value++);
default:
g_warning ("%s called with invalid size parameter", G_STRFUNC); 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 (size)
{
case 1:
GE (glUniform1fv (uniform_no, count, value));
break;
case 2:
GE (glUniform2fv (uniform_no, count, value));
break;
case 3:
GE (glUniform3fv (uniform_no, count, value));
break;
case 4:
GE (glUniform4fv (uniform_no, count, value));
break;
default:
g_warning ("%s called with invalid size parameter", G_STRFUNC);
}
} }
} }
@ -276,6 +414,8 @@ cogl_program_uniform_matrix (int uniform_no,
g_return_if_fail (program != NULL); g_return_if_fail (program != NULL);
g_return_if_fail (program->language != COGL_SHADER_LANGUAGE_ARBFP);
_cogl_gl_use_program_wrapper (program); _cogl_gl_use_program_wrapper (program);
switch (size) switch (size)
@ -293,3 +433,11 @@ cogl_program_uniform_matrix (int uniform_no,
g_warning ("%s called with invalid size parameter", G_STRFUNC); g_warning ("%s called with invalid size parameter", G_STRFUNC);
} }
} }
CoglShaderLanguage
_cogl_program_get_language (CoglHandle handle)
{
CoglProgram *program = handle;
return program->language;
}

View File

@ -25,13 +25,20 @@
#define __COGL_PROGRAM_H #define __COGL_PROGRAM_H
#include "cogl-handle.h" #include "cogl-handle.h"
#include "cogl-shader-private.h"
typedef struct _CoglProgram CoglProgram; typedef struct _CoglProgram CoglProgram;
/* The ARBfp spec says at least 24 indices are available */
#define COGL_PROGRAM_MAX_ARBFP_LOCAL_PARAMS 24
struct _CoglProgram struct _CoglProgram
{ {
CoglHandleObject _parent; CoglHandleObject _parent;
GLuint gl_handle; CoglShaderLanguage language;
float arbfp_local_params[COGL_PROGRAM_MAX_ARBFP_LOCAL_PARAMS][4];
GLuint gl_handle;
gboolean is_linked;
}; };
CoglProgram *_cogl_program_pointer_from_handle (CoglHandle handle); CoglProgram *_cogl_program_pointer_from_handle (CoglHandle handle);

View File

@ -365,3 +365,10 @@ cogl_program_uniform_matrix (int uniform_no,
#endif /* HAVE_COGL_GLES2 */ #endif /* HAVE_COGL_GLES2 */
CoglShaderLanguage
_cogl_program_get_language (CoglHandle handle)
{
return COGL_SHADER_LANGUAGE_GLSL;
}