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;
|
||||
unsigned long authority_cache_age;
|
||||
|
||||
CoglHandle user_program;
|
||||
GString *source;
|
||||
GLuint gl_program;
|
||||
gboolean *sampled;
|
||||
@ -160,7 +161,7 @@ layers_arbfp_would_differ (CoglMaterialLayer **material0_layers,
|
||||
* generate.
|
||||
*/
|
||||
static CoglMaterial *
|
||||
find_arbfp_authority (CoglMaterial *material)
|
||||
find_arbfp_authority (CoglMaterial *material, CoglHandle user_program)
|
||||
{
|
||||
CoglMaterial *authority0;
|
||||
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
|
||||
* arbfp codegen */
|
||||
|
||||
if (user_program != COGL_INVALID_HANDLE)
|
||||
return material;
|
||||
|
||||
/* Find the first material that modifies state that affects the
|
||||
* arbfp codegen... */
|
||||
authority0 = _cogl_material_get_authority (material,
|
||||
@ -253,9 +257,13 @@ _cogl_material_backend_arbfp_start (CoglMaterial *material,
|
||||
CoglMaterial *authority;
|
||||
CoglMaterialBackendARBfpPrivate *priv;
|
||||
CoglMaterialBackendARBfpPrivate *authority_priv;
|
||||
CoglHandle user_program;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
||||
/* First validate that we can handle the current state using ARBfp
|
||||
*/
|
||||
|
||||
if (!cogl_features_available (COGL_FEATURE_SHADERS_ARBFP))
|
||||
return FALSE;
|
||||
|
||||
@ -263,11 +271,23 @@ _cogl_material_backend_arbfp_start (CoglMaterial *material,
|
||||
if (ctx->legacy_fog_state.enabled)
|
||||
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
|
||||
* and the authority. (The oldest ancestor whos state will result in
|
||||
* the same program being generated) The former will simply cache a
|
||||
* pointer to the authority and the later will track the arbfp
|
||||
* program that we will generate.
|
||||
* and the arbfp-authority. The former will simply cache a pointer
|
||||
* to the authority and the later will track the arbfp program that
|
||||
* we will generate.
|
||||
*/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/* 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 &&
|
||||
priv->authority_cache_age != _cogl_material_get_age (material))
|
||||
invalidate_arbfp_authority_cache (material);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Now we have our arbfp-authority fetch the ARBfp backend private
|
||||
* state from it (allocting if necessary) */
|
||||
|
||||
authority = priv->authority_cache;
|
||||
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];
|
||||
|
||||
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 */
|
||||
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);
|
||||
CoglMaterialBackendARBfpPrivate *priv =
|
||||
arbfp_authority->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
|
||||
GLuint gl_program;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
||||
@ -954,9 +985,16 @@ _cogl_material_backend_arbfp_end (CoglMaterial *material,
|
||||
g_free (priv->sampled);
|
||||
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);
|
||||
|
||||
return TRUE;
|
||||
@ -968,17 +1006,23 @@ _cogl_material_backend_arbfp_material_pre_change_notify (
|
||||
CoglMaterialState change,
|
||||
const CoglColor *new_color)
|
||||
{
|
||||
CoglMaterialBackendARBfpPrivate *priv =
|
||||
material->backend_privs[COGL_MATERIAL_BACKEND_ARBFP];
|
||||
CoglMaterialBackendARBfpPrivate *priv;
|
||||
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 */
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK &&
|
||||
priv->gl_program &&
|
||||
change & fragment_op_changes)
|
||||
if (!(material->backend_priv_set_mask & COGL_MATERIAL_BACKEND_ARBFP_MASK) ||
|
||||
!(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));
|
||||
priv->gl_program = 0;
|
||||
|
@ -63,28 +63,20 @@ _cogl_material_backend_glsl_start (CoglMaterial *material,
|
||||
int n_layers,
|
||||
unsigned long materials_difference)
|
||||
{
|
||||
CoglHandle program;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, FALSE);
|
||||
|
||||
if (!cogl_features_available (COGL_FEATURE_SHADERS_GLSL))
|
||||
return FALSE;
|
||||
|
||||
if (materials_difference & COGL_MATERIAL_STATE_USER_SHADER)
|
||||
{
|
||||
CoglMaterial *authority =
|
||||
_cogl_material_get_authority (material,
|
||||
COGL_MATERIAL_STATE_USER_SHADER);
|
||||
CoglHandle program = authority->big_state->user_program;
|
||||
program = cogl_material_get_user_program (material);
|
||||
if (program == COGL_INVALID_HANDLE ||
|
||||
_cogl_program_get_language (program) != COGL_SHADER_LANGUAGE_GLSL)
|
||||
return FALSE; /* XXX: change me when we support code generation here */
|
||||
|
||||
if (program == COGL_INVALID_HANDLE)
|
||||
return FALSE; /* XXX: change me when we support code generation here */
|
||||
|
||||
_cogl_use_program (program, COGL_MATERIAL_PROGRAM_TYPE_GLSL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* TODO: also support code generation */
|
||||
|
||||
return FALSE;
|
||||
_cogl_use_program (program, COGL_MATERIAL_PROGRAM_TYPE_GLSL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
@ -28,13 +28,26 @@
|
||||
|
||||
typedef struct _CoglShader CoglShader;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COGL_SHADER_LANGUAGE_GLSL,
|
||||
#ifdef HAVE_COGL_GL
|
||||
COGL_SHADER_LANGUAGE_ARBFP
|
||||
#endif
|
||||
} CoglShaderLanguage;
|
||||
|
||||
struct _CoglShader
|
||||
{
|
||||
CoglHandleObject _parent;
|
||||
GLuint gl_handle;
|
||||
char *arbfp_source;
|
||||
CoglShaderType type;
|
||||
CoglShaderLanguage language;
|
||||
};
|
||||
|
||||
CoglShader *_cogl_shader_pointer_from_handle (CoglHandle handle);
|
||||
|
||||
CoglShaderLanguage
|
||||
_cogl_program_get_language (CoglHandle handle);
|
||||
|
||||
#endif /* __COGL_SHADER_H */
|
||||
|
@ -33,6 +33,8 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_COGL_GL
|
||||
#define glCreateShader ctx->drv.pf_glCreateShader
|
||||
#define glGetShaderiv ctx->drv.pf_glGetShaderiv
|
||||
@ -58,7 +60,14 @@ _cogl_shader_free (CoglShader *shader)
|
||||
/* Frees shader resources but its handle is not
|
||||
released! Do that separately before this! */
|
||||
_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);
|
||||
}
|
||||
@ -67,23 +76,23 @@ CoglHandle
|
||||
cogl_create_shader (CoglShaderType type)
|
||||
{
|
||||
CoglShader *shader;
|
||||
GLenum gl_type;
|
||||
|
||||
GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
|
||||
|
||||
if (type == COGL_SHADER_TYPE_VERTEX)
|
||||
gl_type = GL_VERTEX_SHADER;
|
||||
else if (type == COGL_SHADER_TYPE_FRAGMENT)
|
||||
gl_type = GL_FRAGMENT_SHADER;
|
||||
else
|
||||
switch (type)
|
||||
{
|
||||
case COGL_SHADER_TYPE_VERTEX:
|
||||
case COGL_SHADER_TYPE_FRAGMENT:
|
||||
break;
|
||||
default:
|
||||
g_warning ("Unexpected shader type (0x%08lX) given to "
|
||||
"cogl_create_shader", (unsigned long) type);
|
||||
return COGL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
shader = g_slice_new (CoglShader);
|
||||
shader->gl_handle = glCreateShader (gl_type);
|
||||
shader->language = COGL_SHADER_LANGUAGE_GLSL;
|
||||
shader->gl_handle = 0;
|
||||
shader->type = type;
|
||||
|
||||
return _cogl_shader_handle_new (shader);
|
||||
@ -94,6 +103,8 @@ cogl_shader_source (CoglHandle handle,
|
||||
const char *source)
|
||||
{
|
||||
CoglShader *shader;
|
||||
CoglShaderLanguage language;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (!cogl_is_shader (handle))
|
||||
@ -101,7 +112,57 @@ cogl_shader_source (CoglHandle 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
|
||||
@ -115,15 +176,14 @@ cogl_shader_compile (CoglHandle 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 *
|
||||
cogl_shader_get_info_log (CoglHandle handle)
|
||||
{
|
||||
CoglShader *shader;
|
||||
char buffer[512];
|
||||
int len = 0;
|
||||
|
||||
GET_CONTEXT (ctx, NULL);
|
||||
|
||||
@ -132,10 +192,21 @@ cogl_shader_get_info_log (CoglHandle handle)
|
||||
|
||||
shader = _cogl_shader_pointer_from_handle (handle);
|
||||
|
||||
glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer);
|
||||
buffer[len] = '\0';
|
||||
|
||||
return g_strdup (buffer);
|
||||
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);
|
||||
buffer[len] = '\0';
|
||||
return g_strdup (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
CoglShaderType
|
||||
@ -168,11 +239,18 @@ cogl_shader_is_compiled (CoglHandle handle)
|
||||
|
||||
shader = _cogl_shader_pointer_from_handle (handle);
|
||||
|
||||
GE (glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status));
|
||||
if (status == GL_TRUE)
|
||||
#ifdef HAVE_COGL_GL
|
||||
if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
|
||||
return TRUE;
|
||||
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 */
|
||||
|
@ -496,6 +496,9 @@ cogl_get_features (void)
|
||||
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_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))
|
||||
ctx->feature_flags &= ~COGL_FEATURE_SHADERS_GLSL;
|
||||
|
||||
@ -521,9 +524,6 @@ _cogl_features_available_private (CoglFeatureFlagsPrivate features)
|
||||
if (!ctx->features_cached)
|
||||
_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;
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,12 @@
|
||||
* 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/>.
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Authors:
|
||||
* Robert Bragg <robert@linux.intel.com>
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@ -36,6 +39,8 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define glCreateProgram ctx->drv.pf_glCreateProgram
|
||||
#define glAttachShader ctx->drv.pf_glAttachShader
|
||||
#define glUseProgram ctx->drv.pf_glUseProgram
|
||||
@ -62,6 +67,13 @@
|
||||
#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);
|
||||
@ -73,7 +85,14 @@ _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);
|
||||
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);
|
||||
}
|
||||
@ -84,8 +103,7 @@ cogl_create_program (void)
|
||||
CoglProgram *program;
|
||||
_COGL_GET_CONTEXT (ctx, NULL);
|
||||
|
||||
program = g_slice_new (CoglProgram);
|
||||
program->gl_handle = glCreateProgram ();
|
||||
program = g_slice_new0 (CoglProgram);
|
||||
|
||||
return _cogl_program_handle_new (program);
|
||||
}
|
||||
@ -96,16 +114,63 @@ cogl_program_attach_shader (CoglHandle program_handle,
|
||||
{
|
||||
CoglProgram *program;
|
||||
CoglShader *shader;
|
||||
CoglShaderLanguage language;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (!cogl_is_program (program_handle) || !cogl_is_shader (shader_handle))
|
||||
return;
|
||||
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);
|
||||
|
||||
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
|
||||
@ -119,7 +184,11 @@ cogl_program_link (CoglHandle 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
|
||||
@ -130,6 +199,12 @@ cogl_program_use (CoglHandle handle)
|
||||
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)
|
||||
@ -142,6 +217,39 @@ cogl_program_use (CoglHandle 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
|
||||
cogl_program_get_uniform_location (CoglHandle handle,
|
||||
const char *uniform_name)
|
||||
@ -154,7 +262,10 @@ cogl_program_get_uniform_location (CoglHandle 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
|
||||
@ -169,6 +280,8 @@ cogl_program_uniform_1f (int uniform_no,
|
||||
|
||||
g_return_if_fail (program != NULL);
|
||||
|
||||
g_return_if_fail (program->language != COGL_SHADER_LANGUAGE_ARBFP);
|
||||
|
||||
_cogl_gl_use_program_wrapper (program);
|
||||
|
||||
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->language != COGL_SHADER_LANGUAGE_ARBFP);
|
||||
|
||||
_cogl_gl_use_program_wrapper (program);
|
||||
|
||||
GE (glUniform1i (uniform_no, value));
|
||||
}
|
||||
|
||||
void
|
||||
cogl_program_uniform_float (int uniform_no,
|
||||
int size,
|
||||
int count,
|
||||
cogl_program_uniform_float (int uniform_no,
|
||||
int size,
|
||||
int count,
|
||||
const GLfloat *value)
|
||||
{
|
||||
CoglProgram *program;
|
||||
@ -205,24 +320,47 @@ cogl_program_uniform_float (int uniform_no,
|
||||
|
||||
g_return_if_fail (program != NULL);
|
||||
|
||||
_cogl_gl_use_program_wrapper (program);
|
||||
|
||||
switch (size)
|
||||
if (program->language == COGL_SHADER_LANGUAGE_ARBFP)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
|
||||
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->language != COGL_SHADER_LANGUAGE_ARBFP);
|
||||
|
||||
_cogl_gl_use_program_wrapper (program);
|
||||
|
||||
switch (size)
|
||||
@ -293,3 +433,11 @@ cogl_program_uniform_matrix (int uniform_no,
|
||||
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
|
||||
|
||||
#include "cogl-handle.h"
|
||||
#include "cogl-shader-private.h"
|
||||
|
||||
typedef struct _CoglProgram CoglProgram;
|
||||
|
||||
/* The ARBfp spec says at least 24 indices are available */
|
||||
#define COGL_PROGRAM_MAX_ARBFP_LOCAL_PARAMS 24
|
||||
|
||||
struct _CoglProgram
|
||||
{
|
||||
CoglHandleObject _parent;
|
||||
GLuint gl_handle;
|
||||
CoglHandleObject _parent;
|
||||
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);
|
||||
|
@ -365,3 +365,10 @@ cogl_program_uniform_matrix (int uniform_no,
|
||||
|
||||
|
||||
#endif /* HAVE_COGL_GLES2 */
|
||||
|
||||
CoglShaderLanguage
|
||||
_cogl_program_get_language (CoglHandle handle)
|
||||
{
|
||||
return COGL_SHADER_LANGUAGE_GLSL;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user