mirror of
https://github.com/brl/mutter.git
synced 2024-12-01 12:20:47 -05:00
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:
parent
5741e28cdc
commit
09e664c349
@ -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;
|
||||||
|
@ -63,30 +63,22 @@ _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,
|
|
||||||
COGL_MATERIAL_STATE_USER_SHADER);
|
|
||||||
CoglHandle program = authority->big_state->user_program;
|
|
||||||
|
|
||||||
if (program == COGL_INVALID_HANDLE)
|
|
||||||
return FALSE; /* XXX: change me when we support code generation here */
|
return FALSE; /* XXX: change me when we support code generation here */
|
||||||
|
|
||||||
_cogl_use_program (program, COGL_MATERIAL_PROGRAM_TYPE_GLSL);
|
_cogl_use_program (program, COGL_MATERIAL_PROGRAM_TYPE_GLSL);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: also support code generation */
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
_cogl_material_backend_glsl_add_layer (CoglMaterial *material,
|
_cogl_material_backend_glsl_add_layer (CoglMaterial *material,
|
||||||
CoglMaterialLayer *layer,
|
CoglMaterialLayer *layer,
|
||||||
|
@ -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 */
|
||||||
|
@ -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,9 +112,59 @@ cogl_shader_source (CoglHandle handle,
|
|||||||
|
|
||||||
shader = _cogl_shader_pointer_from_handle (handle);
|
shader = _cogl_shader_pointer_from_handle (handle);
|
||||||
|
|
||||||
|
#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);
|
glShaderSource (shader->gl_handle, 1, &source, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shader->language = language;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cogl_shader_compile (CoglHandle handle)
|
cogl_shader_compile (CoglHandle handle)
|
||||||
{
|
{
|
||||||
@ -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,11 +192,22 @@ cogl_shader_get_info_log (CoglHandle handle)
|
|||||||
|
|
||||||
shader = _cogl_shader_pointer_from_handle (handle);
|
shader = _cogl_shader_pointer_from_handle (handle);
|
||||||
|
|
||||||
|
if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
|
||||||
|
{
|
||||||
|
/* ARBfp exposes a program error string, but since cogl_program
|
||||||
|
* 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);
|
glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer);
|
||||||
buffer[len] = '\0';
|
buffer[len] = '\0';
|
||||||
|
|
||||||
return g_strdup (buffer);
|
return g_strdup (buffer);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CoglShaderType
|
CoglShaderType
|
||||||
cogl_shader_get_type (CoglHandle handle)
|
cogl_shader_get_type (CoglHandle handle)
|
||||||
@ -168,12 +239,19 @@ cogl_shader_is_compiled (CoglHandle handle)
|
|||||||
|
|
||||||
shader = _cogl_shader_pointer_from_handle (handle);
|
shader = _cogl_shader_pointer_from_handle (handle);
|
||||||
|
|
||||||
|
#ifdef HAVE_COGL_GL
|
||||||
|
if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
|
||||||
|
return TRUE;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
GE (glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status));
|
GE (glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status));
|
||||||
if (status == GL_TRUE)
|
if (status == GL_TRUE)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
else
|
else
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else /* HAVE_COGL_GLES */
|
#else /* HAVE_COGL_GLES */
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
if (program->gl_handle)
|
||||||
|
{
|
||||||
|
if (program->language == COGL_SHADER_LANGUAGE_ARBFP)
|
||||||
|
GE (glDeletePrograms (1, &program->gl_handle));
|
||||||
|
else
|
||||||
GE (glDeleteProgram (program->gl_handle));
|
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,18 +114,65 @@ 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);
|
||||||
|
|
||||||
|
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));
|
GE (glAttachShader (program->gl_handle, shader->gl_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* NB: There is no separation between shader objects and program
|
||||||
|
* objects for ARBfp */
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cogl_program_link (CoglHandle handle)
|
cogl_program_link (CoglHandle handle)
|
||||||
{
|
{
|
||||||
@ -119,7 +184,11 @@ cogl_program_link (CoglHandle handle)
|
|||||||
|
|
||||||
program = _cogl_program_pointer_from_handle (handle);
|
program = _cogl_program_pointer_from_handle (handle);
|
||||||
|
|
||||||
|
if (program->language == COGL_SHADER_LANGUAGE_GLSL &&
|
||||||
|
program->gl_handle)
|
||||||
GE (glLinkProgram (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,6 +262,9 @@ cogl_program_get_uniform_location (CoglHandle handle,
|
|||||||
|
|
||||||
program = _cogl_program_pointer_from_handle (handle);
|
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);
|
return glGetUniformLocation (program->gl_handle, uniform_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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,6 +299,8 @@ 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));
|
||||||
@ -205,6 +320,28 @@ cogl_program_uniform_float (int uniform_no,
|
|||||||
|
|
||||||
g_return_if_fail (program != NULL);
|
g_return_if_fail (program != NULL);
|
||||||
|
|
||||||
|
if (program->language == COGL_SHADER_LANGUAGE_ARBFP)
|
||||||
|
{
|
||||||
|
unsigned int _index = uniform_no;
|
||||||
|
unsigned int index_end = _index + count;
|
||||||
|
int i;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
g_return_if_fail (size == 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);
|
_cogl_gl_use_program_wrapper (program);
|
||||||
|
|
||||||
switch (size)
|
switch (size)
|
||||||
@ -225,6 +362,7 @@ cogl_program_uniform_float (int uniform_no,
|
|||||||
g_warning ("%s called with invalid size parameter", G_STRFUNC);
|
g_warning ("%s called with invalid size parameter", G_STRFUNC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cogl_program_uniform_int (int uniform_no,
|
cogl_program_uniform_int (int uniform_no,
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
CoglShaderLanguage language;
|
||||||
|
float arbfp_local_params[COGL_PROGRAM_MAX_ARBFP_LOCAL_PARAMS][4];
|
||||||
GLuint gl_handle;
|
GLuint gl_handle;
|
||||||
|
gboolean is_linked;
|
||||||
};
|
};
|
||||||
|
|
||||||
CoglProgram *_cogl_program_pointer_from_handle (CoglHandle handle);
|
CoglProgram *_cogl_program_pointer_from_handle (CoglHandle handle);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user