diff options
Diffstat (limited to 'cogl/cogl/driver/gl')
32 files changed, 0 insertions, 11971 deletions
diff --git a/cogl/cogl/driver/gl/cogl-attribute-gl-private.h b/cogl/cogl/driver/gl/cogl-attribute-gl-private.h deleted file mode 100644 index 8370621e3..000000000 --- a/cogl/cogl/driver/gl/cogl-attribute-gl-private.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2012 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Robert Bragg <robert@linux.intel.com> - */ - -#ifndef _COGL_ATTRIBUTE_GL_PRIVATE_H_ -#define _COGL_ATTRIBUTE_GL_PRIVATE_H_ - -#include "cogl-types.h" -#include "cogl-framebuffer.h" -#include "cogl-attribute.h" -#include "cogl-attribute-private.h" - -void -_cogl_gl_flush_attributes_state (CoglFramebuffer *framebuffer, - CoglPipeline *pipeline, - CoglFlushLayerState *layers_state, - CoglDrawFlags flags, - CoglAttribute **attributes, - int n_attributes); - -#endif /* _COGL_ATTRIBUTE_GL_PRIVATE_H_ */ diff --git a/cogl/cogl/driver/gl/cogl-attribute-gl.c b/cogl/cogl/driver/gl/cogl-attribute-gl.c deleted file mode 100644 index d619e286f..000000000 --- a/cogl/cogl/driver/gl/cogl-attribute-gl.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2010,2011,2012 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Neil Roberts <neil@linux.intel.com> - * Robert Bragg <robert@linux.intel.com> - */ - -#include "cogl-config.h" - -#include <string.h> - -#include "cogl-private.h" -#include "cogl-context-private.h" -#include "cogl-attribute.h" -#include "cogl-attribute-private.h" -#include "driver/gl/cogl-attribute-gl-private.h" -#include "driver/gl/cogl-buffer-gl-private.h" -#include "driver/gl/cogl-pipeline-opengl-private.h" -#include "driver/gl/cogl-pipeline-progend-glsl-private.h" -#include "driver/gl/cogl-util-gl-private.h" - -typedef struct _ForeachChangedBitState -{ - CoglContext *context; - const CoglBitmask *new_bits; - CoglPipeline *pipeline; -} ForeachChangedBitState; - -static gboolean -toggle_custom_attribute_enabled_cb (int bit_num, void *user_data) -{ - ForeachChangedBitState *state = user_data; - gboolean enabled = _cogl_bitmask_get (state->new_bits, bit_num); - CoglContext *context = state->context; - - if (enabled) - GE( context, glEnableVertexAttribArray (bit_num) ); - else - GE( context, glDisableVertexAttribArray (bit_num) ); - - return TRUE; -} - -static void -foreach_changed_bit_and_save (CoglContext *context, - CoglBitmask *current_bits, - const CoglBitmask *new_bits, - CoglBitmaskForeachFunc callback, - ForeachChangedBitState *state) -{ - /* Get the list of bits that are different */ - _cogl_bitmask_clear_all (&context->changed_bits_tmp); - _cogl_bitmask_set_bits (&context->changed_bits_tmp, current_bits); - _cogl_bitmask_xor_bits (&context->changed_bits_tmp, new_bits); - - /* Iterate over each bit to change */ - state->new_bits = new_bits; - _cogl_bitmask_foreach (&context->changed_bits_tmp, - callback, - state); - - /* Store the new values */ - _cogl_bitmask_clear_all (current_bits); - _cogl_bitmask_set_bits (current_bits, new_bits); -} - -static void -setup_generic_buffered_attribute (CoglContext *context, - CoglPipeline *pipeline, - CoglAttribute *attribute, - uint8_t *base) -{ - int name_index = attribute->name_state->name_index; - int attrib_location = - _cogl_pipeline_progend_glsl_get_attrib_location (pipeline, name_index); - - if (attrib_location == -1) - return; - - GE( context, glVertexAttribPointer (attrib_location, - attribute->d.buffered.n_components, - attribute->d.buffered.type, - attribute->normalized, - attribute->d.buffered.stride, - base + attribute->d.buffered.offset) ); - _cogl_bitmask_set (&context->enable_custom_attributes_tmp, - attrib_location, TRUE); -} - -static void -setup_generic_const_attribute (CoglContext *context, - CoglPipeline *pipeline, - CoglAttribute *attribute) -{ - int name_index = attribute->name_state->name_index; - int attrib_location = - _cogl_pipeline_progend_glsl_get_attrib_location (pipeline, name_index); - int columns; - int i; - - if (attrib_location == -1) - return; - - if (attribute->d.constant.boxed.type == COGL_BOXED_MATRIX) - columns = attribute->d.constant.boxed.size; - else - columns = 1; - - /* Note: it's ok to access a COGL_BOXED_FLOAT as a matrix with only - * one column... */ - - switch (attribute->d.constant.boxed.size) - { - case 1: - GE( context, glVertexAttrib1fv (attrib_location, - attribute->d.constant.boxed.v.matrix)); - break; - case 2: - for (i = 0; i < columns; i++) - GE( context, glVertexAttrib2fv (attrib_location + i, - attribute->d.constant.boxed.v.matrix)); - break; - case 3: - for (i = 0; i < columns; i++) - GE( context, glVertexAttrib3fv (attrib_location + i, - attribute->d.constant.boxed.v.matrix)); - break; - case 4: - for (i = 0; i < columns; i++) - GE( context, glVertexAttrib4fv (attrib_location + i, - attribute->d.constant.boxed.v.matrix)); - break; - default: - g_warn_if_reached (); - } -} - -static void -apply_attribute_enable_updates (CoglContext *context, - CoglPipeline *pipeline) -{ - ForeachChangedBitState changed_bits_state; - - changed_bits_state.context = context; - changed_bits_state.pipeline = pipeline; - changed_bits_state.new_bits = &context->enable_custom_attributes_tmp; - foreach_changed_bit_and_save (context, - &context->enabled_custom_attributes, - &context->enable_custom_attributes_tmp, - toggle_custom_attribute_enabled_cb, - &changed_bits_state); -} - -void -_cogl_gl_flush_attributes_state (CoglFramebuffer *framebuffer, - CoglPipeline *pipeline, - CoglFlushLayerState *layers_state, - CoglDrawFlags flags, - CoglAttribute **attributes, - int n_attributes) -{ - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - int i; - gboolean with_color_attrib = FALSE; - gboolean unknown_color_alpha = FALSE; - CoglPipeline *copy = NULL; - - /* Iterate the attributes to see if we have a color attribute which - * may affect our decision to enable blending or not. - * - * We need to do this before flushing the pipeline. */ - for (i = 0; i < n_attributes; i++) - switch (attributes[i]->name_state->name_id) - { - case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY: - if ((flags & COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE) == 0 && - _cogl_attribute_get_n_components (attributes[i]) == 4) - unknown_color_alpha = TRUE; - with_color_attrib = TRUE; - break; - - default: - break; - } - - if (G_UNLIKELY (layers_state->options.flags)) - { - /* If we haven't already created a derived pipeline... */ - if (!copy) - { - copy = cogl_pipeline_copy (pipeline); - pipeline = copy; - } - _cogl_pipeline_apply_overrides (pipeline, &layers_state->options); - - /* TODO: - * overrides = cogl_pipeline_get_data (pipeline, - * last_overrides_key); - * if (overrides) - * { - * age = cogl_pipeline_get_age (pipeline); - * XXX: actually we also need to check for legacy_state - * if (overrides->ags != age || - * memcmp (&overrides->options, &options, - * sizeof (options) != 0) - * { - * cogl_object_unref (overrides->weak_pipeline); - * g_free (overrides); - * overrides = NULL; - * } - * } - * if (!overrides) - * { - * overrides = g_new0 (Overrides, 1); - * overrides->weak_pipeline = - * cogl_pipeline_weak_copy (pipeline); - * _cogl_pipeline_apply_overrides (overrides->weak_pipeline, - * &options); - * - * cogl_pipeline_set_data (pipeline, last_overrides_key, - * weak_overrides, - * free_overrides_cb, - * NULL); - * } - * pipeline = overrides->weak_pipeline; - */ - } - - _cogl_pipeline_flush_gl_state (ctx, - pipeline, - framebuffer, - with_color_attrib, - unknown_color_alpha); - - _cogl_bitmask_clear_all (&ctx->enable_custom_attributes_tmp); - - /* Bind the attribute pointers. We need to do this after the - * pipeline is flushed because when using GLSL that is the only - * point when we can determine the attribute locations */ - - for (i = 0; i < n_attributes; i++) - { - CoglAttribute *attribute = attributes[i]; - CoglAttributeBuffer *attribute_buffer; - CoglBuffer *buffer; - uint8_t *base; - - if (attribute->is_buffered) - { - attribute_buffer = cogl_attribute_get_buffer (attribute); - buffer = COGL_BUFFER (attribute_buffer); - - /* Note: we don't try and catch errors with binding buffers - * here since OOM errors at this point indicate that nothing - * has yet been uploaded to attribute buffer which we - * consider to be a programmer error. - */ - base = - _cogl_buffer_gl_bind (buffer, - COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER, - NULL); - - setup_generic_buffered_attribute (ctx, pipeline, attribute, base); - - _cogl_buffer_gl_unbind (buffer); - } - else - { - setup_generic_const_attribute (ctx, pipeline, attribute); - } - } - - apply_attribute_enable_updates (ctx, pipeline); - - if (copy) - cogl_object_unref (copy); -} diff --git a/cogl/cogl/driver/gl/cogl-bitmap-gl-private.h b/cogl/cogl/driver/gl/cogl-bitmap-gl-private.h deleted file mode 100644 index b2726c421..000000000 --- a/cogl/cogl/driver/gl/cogl-bitmap-gl-private.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2007 OpenedHand - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - */ - -#ifndef __COGL_BITMAP_GL_PRIVATE_H -#define __COGL_BITMAP_GL_PRIVATE_H - -#include "cogl-bitmap-private.h" - -/* These two are replacements for map and unmap that should used when - * the pointer is going to be passed to GL for pixel packing or - * unpacking. The address might not be valid for reading if the bitmap - * was created with new_from_buffer but it will however be good to - * pass to glTexImage2D for example. The access should be READ for - * unpacking and WRITE for packing. It can not be both - */ -uint8_t * -_cogl_bitmap_gl_bind (CoglBitmap *bitmap, - CoglBufferAccess access, - CoglBufferMapHint hints, - GError **error); - -void -_cogl_bitmap_gl_unbind (CoglBitmap *bitmap); - -#endif /* __COGL_BITMAP_GL_PRIVATE_H */ diff --git a/cogl/cogl/driver/gl/cogl-bitmap-gl.c b/cogl/cogl/driver/gl/cogl-bitmap-gl.c deleted file mode 100644 index 8011d7fc8..000000000 --- a/cogl/cogl/driver/gl/cogl-bitmap-gl.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2007,2008,2009 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - */ - -#include "cogl-config.h" - -#include "cogl-util.h" -#include "cogl-debug.h" -#include "cogl-private.h" -#include "cogl-bitmap-private.h" -#include "cogl-buffer-private.h" -#include "cogl-pixel-buffer.h" -#include "cogl-context-private.h" -#include "cogl-gtype-private.h" -#include "cogl-buffer-gl-private.h" -#include "cogl-bitmap-gl-private.h" - -uint8_t * -_cogl_bitmap_gl_bind (CoglBitmap *bitmap, - CoglBufferAccess access, - CoglBufferMapHint hints, - GError **error) -{ - uint8_t *ptr; - GError *internal_error = NULL; - - g_return_val_if_fail (access & (COGL_BUFFER_ACCESS_READ | - COGL_BUFFER_ACCESS_WRITE), - NULL); - - /* Divert to another bitmap if this data is shared */ - if (bitmap->shared_bmp) - return _cogl_bitmap_gl_bind (bitmap->shared_bmp, access, hints, error); - - g_return_val_if_fail (!bitmap->bound, NULL); - - /* If the bitmap wasn't created from a buffer then the - implementation of bind is the same as map */ - if (bitmap->buffer == NULL) - { - uint8_t *data = _cogl_bitmap_map (bitmap, access, hints, error); - if (data) - bitmap->bound = TRUE; - return data; - } - - if (access == COGL_BUFFER_ACCESS_READ) - ptr = _cogl_buffer_gl_bind (bitmap->buffer, - COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK, - &internal_error); - else if (access == COGL_BUFFER_ACCESS_WRITE) - ptr = _cogl_buffer_gl_bind (bitmap->buffer, - COGL_BUFFER_BIND_TARGET_PIXEL_PACK, - &internal_error); - else - { - ptr = NULL; - g_assert_not_reached (); - return NULL; - } - - /* NB: _cogl_buffer_gl_bind() may return NULL in non-error - * conditions so we have to explicitly check internal_error to see - * if an exception was thrown */ - if (internal_error) - { - g_propagate_error (error, internal_error); - return NULL; - } - - bitmap->bound = TRUE; - - /* The data pointer actually stores the offset */ - return ptr + GPOINTER_TO_INT (bitmap->data); -} - -void -_cogl_bitmap_gl_unbind (CoglBitmap *bitmap) -{ - /* Divert to another bitmap if this data is shared */ - if (bitmap->shared_bmp) - { - _cogl_bitmap_gl_unbind (bitmap->shared_bmp); - return; - } - - g_assert (bitmap->bound); - bitmap->bound = FALSE; - - /* If the bitmap wasn't created from a pixel array then the - implementation of unbind is the same as unmap */ - if (bitmap->buffer) - _cogl_buffer_gl_unbind (bitmap->buffer); - else - _cogl_bitmap_unmap (bitmap); -} diff --git a/cogl/cogl/driver/gl/cogl-buffer-gl-private.h b/cogl/cogl/driver/gl/cogl-buffer-gl-private.h deleted file mode 100644 index 61807f17e..000000000 --- a/cogl/cogl/driver/gl/cogl-buffer-gl-private.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2012 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Robert Bragg <robert@linux.intel.com> - */ - -#ifndef _COGL_BUFFER_GL_PRIVATE_H_ -#define _COGL_BUFFER_GL_PRIVATE_H_ - -#include "cogl-types.h" -#include "cogl-context.h" -#include "cogl-buffer.h" -#include "cogl-buffer-private.h" - -void -_cogl_buffer_gl_create (CoglBuffer *buffer); - -void -_cogl_buffer_gl_destroy (CoglBuffer *buffer); - -void * -_cogl_buffer_gl_map_range (CoglBuffer *buffer, - size_t offset, - size_t size, - CoglBufferAccess access, - CoglBufferMapHint hints, - GError **error); - -void -_cogl_buffer_gl_unmap (CoglBuffer *buffer); - -gboolean -_cogl_buffer_gl_set_data (CoglBuffer *buffer, - unsigned int offset, - const void *data, - unsigned int size, - GError **error); - -void * -_cogl_buffer_gl_bind (CoglBuffer *buffer, - CoglBufferBindTarget target, - GError **error); - -void -_cogl_buffer_gl_unbind (CoglBuffer *buffer); - -#endif /* _COGL_BUFFER_GL_PRIVATE_H_ */ diff --git a/cogl/cogl/driver/gl/cogl-buffer-gl.c b/cogl/cogl/driver/gl/cogl-buffer-gl.c deleted file mode 100644 index cca19719f..000000000 --- a/cogl/cogl/driver/gl/cogl-buffer-gl.c +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2010,2011,2012,2013 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Damien Lespiau <damien.lespiau@intel.com> - * Robert Bragg <robert@linux.intel.com> - */ - -#include "cogl-config.h" - -#include "cogl-context-private.h" -#include "driver/gl/cogl-buffer-gl-private.h" -#include "driver/gl/cogl-util-gl-private.h" - -/* - * GL/GLES compatibility defines for the buffer API: - */ - -#ifndef GL_PIXEL_PACK_BUFFER -#define GL_PIXEL_PACK_BUFFER 0x88EB -#endif -#ifndef GL_PIXEL_UNPACK_BUFFER -#define GL_PIXEL_UNPACK_BUFFER 0x88EC -#endif -#ifndef GL_ARRAY_BUFFER -#define GL_ARRAY_BUFFER 0x8892 -#endif -#ifndef GL_ELEMENT_ARRAY_BUFFER -#define GL_ARRAY_BUFFER 0x8893 -#endif -#ifndef GL_READ_ONLY -#define GL_READ_ONLY 0x88B8 -#endif -#ifndef GL_WRITE_ONLY -#define GL_WRITE_ONLY 0x88B9 -#endif -#ifndef GL_READ_WRITE -#define GL_READ_WRITE 0x88BA -#endif -#ifndef GL_MAP_READ_BIT -#define GL_MAP_READ_BIT 0x0001 -#endif -#ifndef GL_MAP_WRITE_BIT -#define GL_MAP_WRITE_BIT 0x0002 -#endif -#ifndef GL_MAP_INVALIDATE_RANGE_BIT -#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 -#endif -#ifndef GL_MAP_INVALIDATE_BUFFER_BIT -#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 -#endif - -void -_cogl_buffer_gl_create (CoglBuffer *buffer) -{ - CoglContext *ctx = buffer->context; - - GE (ctx, glGenBuffers (1, &buffer->gl_handle)); -} - -void -_cogl_buffer_gl_destroy (CoglBuffer *buffer) -{ - GE( buffer->context, glDeleteBuffers (1, &buffer->gl_handle) ); -} - -static GLenum -update_hints_to_gl_enum (CoglBuffer *buffer) -{ - /* usage hint is always DRAW for now */ - switch (buffer->update_hint) - { - case COGL_BUFFER_UPDATE_HINT_STATIC: - return GL_STATIC_DRAW; - case COGL_BUFFER_UPDATE_HINT_DYNAMIC: - return GL_DYNAMIC_DRAW; - - case COGL_BUFFER_UPDATE_HINT_STREAM: - /* OpenGL ES 1.1 only knows about STATIC_DRAW and DYNAMIC_DRAW */ -#if defined(HAVE_COGL_GL) || defined(HAVE_COGL_GLES2) - return GL_STREAM_DRAW; -#else - return GL_DYNAMIC_DRAW; -#endif - } - - g_assert_not_reached (); - return 0; -} - -static GLenum -convert_bind_target_to_gl_target (CoglBufferBindTarget target) -{ - switch (target) - { - case COGL_BUFFER_BIND_TARGET_PIXEL_PACK: - return GL_PIXEL_PACK_BUFFER; - case COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK: - return GL_PIXEL_UNPACK_BUFFER; - case COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER: - return GL_ARRAY_BUFFER; - case COGL_BUFFER_BIND_TARGET_INDEX_BUFFER: - return GL_ELEMENT_ARRAY_BUFFER; - default: - g_return_val_if_reached (COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK); - } -} - -static gboolean -recreate_store (CoglBuffer *buffer, - GError **error) -{ - CoglContext *ctx = buffer->context; - GLenum gl_target; - GLenum gl_enum; - - /* This assumes the buffer is already bound */ - - gl_target = convert_bind_target_to_gl_target (buffer->last_target); - gl_enum = update_hints_to_gl_enum (buffer); - - /* Clear any GL errors */ - _cogl_gl_util_clear_gl_errors (ctx); - - ctx->glBufferData (gl_target, - buffer->size, - NULL, - gl_enum); - - if (_cogl_gl_util_catch_out_of_memory (ctx, error)) - return FALSE; - - buffer->store_created = TRUE; - return TRUE; -} - -static GLenum -_cogl_buffer_access_to_gl_enum (CoglBufferAccess access) -{ - if ((access & COGL_BUFFER_ACCESS_READ_WRITE) == COGL_BUFFER_ACCESS_READ_WRITE) - return GL_READ_WRITE; - else if (access & COGL_BUFFER_ACCESS_WRITE) - return GL_WRITE_ONLY; - else - return GL_READ_ONLY; -} - -static void * -_cogl_buffer_bind_no_create (CoglBuffer *buffer, - CoglBufferBindTarget target) -{ - CoglContext *ctx = buffer->context; - - g_return_val_if_fail (buffer != NULL, NULL); - - /* Don't allow binding the buffer to multiple targets at the same time */ - g_return_val_if_fail (ctx->current_buffer[buffer->last_target] != buffer, - NULL); - - /* Don't allow nesting binds to the same target */ - g_return_val_if_fail (ctx->current_buffer[target] == NULL, NULL); - - buffer->last_target = target; - ctx->current_buffer[target] = buffer; - - if (buffer->flags & COGL_BUFFER_FLAG_BUFFER_OBJECT) - { - GLenum gl_target = convert_bind_target_to_gl_target (buffer->last_target); - GE( ctx, glBindBuffer (gl_target, buffer->gl_handle) ); - return NULL; - } - else - return buffer->data; -} - -void * -_cogl_buffer_gl_map_range (CoglBuffer *buffer, - size_t offset, - size_t size, - CoglBufferAccess access, - CoglBufferMapHint hints, - GError **error) -{ - uint8_t *data; - CoglBufferBindTarget target; - GLenum gl_target; - CoglContext *ctx = buffer->context; - - if (((access & COGL_BUFFER_ACCESS_READ) && - !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ)) || - ((access & COGL_BUFFER_ACCESS_WRITE) && - !cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE))) - { - g_set_error_literal (error, - COGL_SYSTEM_ERROR, - COGL_SYSTEM_ERROR_UNSUPPORTED, - "Tried to map a buffer with unsupported access mode"); - return NULL; - } - - target = buffer->last_target; - _cogl_buffer_bind_no_create (buffer, target); - - gl_target = convert_bind_target_to_gl_target (target); - - if ((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE) && - offset == 0 && size >= buffer->size) - hints |= COGL_BUFFER_MAP_HINT_DISCARD; - - /* If the map buffer range extension is supported then we will - * always use it even if we are mapping the full range because the - * normal mapping function doesn't support passing the discard - * hints */ - if (ctx->glMapBufferRange) - { - GLbitfield gl_access = 0; - gboolean should_recreate_store = !buffer->store_created; - - if ((access & COGL_BUFFER_ACCESS_READ)) - gl_access |= GL_MAP_READ_BIT; - if ((access & COGL_BUFFER_ACCESS_WRITE)) - gl_access |= GL_MAP_WRITE_BIT; - - if ((hints & COGL_BUFFER_MAP_HINT_DISCARD)) - { - /* glMapBufferRange generates an error if you pass the - * discard hint along with asking for read access. However - * it can make sense to ask for both if write access is also - * requested so that the application can immediately read - * back what it just wrote. To work around the restriction - * in GL we just recreate the buffer storage in that case - * which is an alternative way to indicate that the buffer - * contents can be discarded. */ - if ((access & COGL_BUFFER_ACCESS_READ)) - should_recreate_store = TRUE; - else - gl_access |= GL_MAP_INVALIDATE_BUFFER_BIT; - } - else if ((hints & COGL_BUFFER_MAP_HINT_DISCARD_RANGE) && - !(access & COGL_BUFFER_ACCESS_READ)) - gl_access |= GL_MAP_INVALIDATE_RANGE_BIT; - - if (should_recreate_store) - { - if (!recreate_store (buffer, error)) - { - _cogl_buffer_gl_unbind (buffer); - return NULL; - } - } - - /* Clear any GL errors */ - _cogl_gl_util_clear_gl_errors (ctx); - - data = ctx->glMapBufferRange (gl_target, - offset, - size, - gl_access); - - if (_cogl_gl_util_catch_out_of_memory (ctx, error)) - { - _cogl_buffer_gl_unbind (buffer); - return NULL; - } - - g_return_val_if_fail (data != NULL, NULL); - } - else - { - /* create an empty store if we don't have one yet. creating the store - * lazily allows the user of the CoglBuffer to set a hint before the - * store is created. */ - if (!buffer->store_created || - (hints & COGL_BUFFER_MAP_HINT_DISCARD)) - { - if (!recreate_store (buffer, error)) - { - _cogl_buffer_gl_unbind (buffer); - return NULL; - } - } - - /* Clear any GL errors */ - _cogl_gl_util_clear_gl_errors (ctx); - - data = ctx->glMapBuffer (gl_target, - _cogl_buffer_access_to_gl_enum (access)); - - if (_cogl_gl_util_catch_out_of_memory (ctx, error)) - { - _cogl_buffer_gl_unbind (buffer); - return NULL; - } - - g_return_val_if_fail (data != NULL, NULL); - - data += offset; - } - - if (data) - buffer->flags |= COGL_BUFFER_FLAG_MAPPED; - - _cogl_buffer_gl_unbind (buffer); - - return data; -} - -void -_cogl_buffer_gl_unmap (CoglBuffer *buffer) -{ - CoglContext *ctx = buffer->context; - - _cogl_buffer_bind_no_create (buffer, buffer->last_target); - - GE( ctx, glUnmapBuffer (convert_bind_target_to_gl_target - (buffer->last_target)) ); - buffer->flags &= ~COGL_BUFFER_FLAG_MAPPED; - - _cogl_buffer_gl_unbind (buffer); -} - -gboolean -_cogl_buffer_gl_set_data (CoglBuffer *buffer, - unsigned int offset, - const void *data, - unsigned int size, - GError **error) -{ - CoglBufferBindTarget target; - GLenum gl_target; - CoglContext *ctx = buffer->context; - gboolean status = TRUE; - GError *internal_error = NULL; - - target = buffer->last_target; - - _cogl_buffer_gl_bind (buffer, target, &internal_error); - - /* NB: _cogl_buffer_gl_bind() may return NULL in non-error - * conditions so we have to explicitly check internal_error - * to see if an exception was thrown. - */ - if (internal_error) - { - g_propagate_error (error, internal_error); - return FALSE; - } - - gl_target = convert_bind_target_to_gl_target (target); - - /* Clear any GL errors */ - _cogl_gl_util_clear_gl_errors (ctx); - - ctx->glBufferSubData (gl_target, offset, size, data); - - if (_cogl_gl_util_catch_out_of_memory (ctx, error)) - status = FALSE; - - _cogl_buffer_gl_unbind (buffer); - - return status; -} - -void * -_cogl_buffer_gl_bind (CoglBuffer *buffer, - CoglBufferBindTarget target, - GError **error) -{ - void *ret; - - ret = _cogl_buffer_bind_no_create (buffer, target); - - /* create an empty store if we don't have one yet. creating the store - * lazily allows the user of the CoglBuffer to set a hint before the - * store is created. */ - if ((buffer->flags & COGL_BUFFER_FLAG_BUFFER_OBJECT) && - !buffer->store_created) - { - if (!recreate_store (buffer, error)) - { - _cogl_buffer_gl_unbind (buffer); - return NULL; - } - } - - return ret; -} - -void -_cogl_buffer_gl_unbind (CoglBuffer *buffer) -{ - CoglContext *ctx = buffer->context; - - g_return_if_fail (buffer != NULL); - - /* the unbind should pair up with a previous bind */ - g_return_if_fail (ctx->current_buffer[buffer->last_target] == buffer); - - if (buffer->flags & COGL_BUFFER_FLAG_BUFFER_OBJECT) - { - GLenum gl_target = convert_bind_target_to_gl_target (buffer->last_target); - GE( ctx, glBindBuffer (gl_target, 0) ); - } - - ctx->current_buffer[buffer->last_target] = NULL; -} diff --git a/cogl/cogl/driver/gl/cogl-clip-stack-gl-private.h b/cogl/cogl/driver/gl/cogl-clip-stack-gl-private.h deleted file mode 100644 index ff22d2660..000000000 --- a/cogl/cogl/driver/gl/cogl-clip-stack-gl-private.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2012 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Robert Bragg <robert@linux.intel.com> - */ - -#ifndef _COGL_CLIP_STACK_GL_PRIVATE_H_ -#define _COGL_CLIP_STACK_GL_PRIVATE_H_ - -#include "cogl-types.h" -#include "cogl-framebuffer.h" -#include "cogl-clip-stack.h" - -void -_cogl_clip_stack_gl_flush (CoglClipStack *stack, - CoglFramebuffer *framebuffer); - -#endif /* _COGL_CLIP_STACK_GL_PRIVATE_H_ */ diff --git a/cogl/cogl/driver/gl/cogl-clip-stack-gl.c b/cogl/cogl/driver/gl/cogl-clip-stack-gl.c deleted file mode 100644 index a693903b3..000000000 --- a/cogl/cogl/driver/gl/cogl-clip-stack-gl.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2007,2008,2009,2010,2011,2012 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Neil Roberts <neil@linux.intel.com> - * Robert Bragg <robert@linux.intel.com> - */ - -#include "cogl-config.h" - -#include "cogl-context-private.h" -#include "cogl-graphene.h" -#include "cogl-primitives-private.h" -#include "cogl-primitive-private.h" -#include "driver/gl/cogl-util-gl-private.h" -#include "driver/gl/cogl-pipeline-opengl-private.h" -#include "driver/gl/cogl-clip-stack-gl-private.h" - -static void -add_stencil_clip_rectangle (CoglFramebuffer *framebuffer, - CoglMatrixEntry *modelview_entry, - float x_1, - float y_1, - float x_2, - float y_2, - gboolean merge) -{ - CoglMatrixStack *projection_stack = - _cogl_framebuffer_get_projection_stack (framebuffer); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - CoglMatrixEntry *old_projection_entry, *old_modelview_entry; - - /* NB: This can be called while flushing the journal so we need - * to be very conservative with what state we change. - */ - old_projection_entry = g_steal_pointer (&ctx->current_projection_entry); - old_modelview_entry = g_steal_pointer (&ctx->current_modelview_entry); - - ctx->current_projection_entry = projection_stack->last_entry; - ctx->current_modelview_entry = modelview_entry; - - GE( ctx, glColorMask (FALSE, FALSE, FALSE, FALSE) ); - GE( ctx, glDepthMask (FALSE) ); - GE( ctx, glStencilMask (0x3) ); - - if (merge) - { - /* Add one to every pixel of the stencil buffer in the - rectangle */ - GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x3) ); - GE( ctx, glStencilOp (GL_INCR, GL_INCR, GL_INCR) ); - _cogl_rectangle_immediate (framebuffer, - ctx->stencil_pipeline, - x_1, y_1, x_2, y_2); - - /* Subtract one from all pixels in the stencil buffer so that - only pixels where both the original stencil buffer and the - rectangle are set will be valid */ - GE( ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR) ); - - ctx->current_projection_entry = &ctx->identity_entry; - ctx->current_modelview_entry = &ctx->identity_entry; - - _cogl_rectangle_immediate (framebuffer, - ctx->stencil_pipeline, - -1.0, -1.0, 1.0, 1.0); - } - else - { - GE( ctx, glEnable (GL_STENCIL_TEST) ); - - /* Initially disallow everything */ - GE( ctx, glClearStencil (0) ); - GE( ctx, glClear (GL_STENCIL_BUFFER_BIT) ); - - /* Punch out a hole to allow the rectangle */ - GE( ctx, glStencilFunc (GL_ALWAYS, 0x1, 0x1) ); - GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE) ); - _cogl_rectangle_immediate (framebuffer, - ctx->stencil_pipeline, - x_1, y_1, x_2, y_2); - } - - ctx->current_projection_entry = old_projection_entry; - ctx->current_modelview_entry = old_modelview_entry; - - /* Restore the stencil mode */ - GE( ctx, glDepthMask (TRUE) ); - GE( ctx, glColorMask (TRUE, TRUE, TRUE, TRUE) ); - GE( ctx, glStencilMask (0x0) ); - GE( ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1) ); - GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) ); -} - -static void -add_stencil_clip_region (CoglFramebuffer *framebuffer, - cairo_region_t *region, - gboolean merge) -{ - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - CoglMatrixEntry *old_projection_entry, *old_modelview_entry; - graphene_matrix_t matrix; - int num_rectangles = cairo_region_num_rectangles (region); - int i; - CoglVertexP2 *vertices; - graphene_point3d_t p; - - /* NB: This can be called while flushing the journal so we need - * to be very conservative with what state we change. - */ - old_projection_entry = g_steal_pointer (&ctx->current_projection_entry); - old_modelview_entry = g_steal_pointer (&ctx->current_modelview_entry); - - ctx->current_projection_entry = &ctx->identity_entry; - ctx->current_modelview_entry = &ctx->identity_entry; - - /* The coordinates in the region are meant to be window coordinates, - * make a matrix that translates those across the viewport, and into - * the default [-1, -1, 1, 1] range. - */ - graphene_point3d_init (&p, - - cogl_framebuffer_get_viewport_x (framebuffer), - - cogl_framebuffer_get_viewport_y (framebuffer), - 0); - - graphene_matrix_init_translate (&matrix, &p); - graphene_matrix_scale (&matrix, - 2.0 / cogl_framebuffer_get_viewport_width (framebuffer), - - 2.0 / cogl_framebuffer_get_viewport_height (framebuffer), - 1); - graphene_matrix_translate (&matrix, &GRAPHENE_POINT3D_INIT (-1.f, 1.f, 0.f)); - - GE( ctx, glColorMask (FALSE, FALSE, FALSE, FALSE) ); - GE( ctx, glDepthMask (FALSE) ); - GE( ctx, glStencilMask (0x3) ); - - if (merge) - { - GE( ctx, glStencilFunc (GL_ALWAYS, 0x1, 0x3) ); - GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_INCR) ); - } - else - { - GE( ctx, glEnable (GL_STENCIL_TEST) ); - - /* Initially disallow everything */ - GE( ctx, glClearStencil (0) ); - GE( ctx, glClear (GL_STENCIL_BUFFER_BIT) ); - - /* Punch out holes to allow the rectangles */ - GE( ctx, glStencilFunc (GL_ALWAYS, 0x1, 0x1) ); - GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE) ); - } - - vertices = g_alloca (sizeof (CoglVertexP2) * num_rectangles * 6); - - for (i = 0; i < num_rectangles; i++) - { - cairo_rectangle_int_t rect; - float x1, y1, z1, w1; - float x2, y2, z2, w2; - CoglVertexP2 *v = vertices + i * 6; - - cairo_region_get_rectangle (region, i, &rect); - - x1 = rect.x; - y1 = rect.y; - z1 = 0.f; - w1 = 1.f; - - x2 = rect.x + rect.width; - y2 = rect.y + rect.height; - z2 = 0.f; - w2 = 1.f; - - cogl_graphene_matrix_project_point (&matrix, &x1, &y1, &z1, &w1); - cogl_graphene_matrix_project_point (&matrix, &x2, &y2, &z2, &w2); - - v[0].x = x1; - v[0].y = y1; - v[1].x = x1; - v[1].y = y2; - v[2].x = x2; - v[2].y = y1; - v[3].x = x1; - v[3].y = y2; - v[4].x = x2; - v[4].y = y2; - v[5].x = x2; - v[5].y = y1; - } - - cogl_2d_primitives_immediate (framebuffer, - ctx->stencil_pipeline, - COGL_VERTICES_MODE_TRIANGLES, - vertices, - 6 * num_rectangles); - - if (merge) - { - /* Subtract one from all pixels in the stencil buffer so that - * only pixels where both the original stencil buffer and the - * region are set will be valid - */ - GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_DECR) ); - _cogl_rectangle_immediate (framebuffer, - ctx->stencil_pipeline, - -1.0, -1.0, 1.0, 1.0); - } - - ctx->current_projection_entry = old_projection_entry; - ctx->current_modelview_entry = old_modelview_entry; - - /* Restore the stencil mode */ - GE (ctx, glDepthMask (TRUE)); - GE (ctx, glColorMask (TRUE, TRUE, TRUE, TRUE)); - GE( ctx, glStencilMask (0x0) ); - GE( ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1) ); - GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) ); -} - -typedef void (*SilhouettePaintCallback) (CoglFramebuffer *framebuffer, - CoglPipeline *pipeline, - void *user_data); - -static void -add_stencil_clip_silhouette (CoglFramebuffer *framebuffer, - SilhouettePaintCallback silhouette_callback, - CoglMatrixEntry *modelview_entry, - float bounds_x1, - float bounds_y1, - float bounds_x2, - float bounds_y2, - gboolean merge, - gboolean need_clear, - void *user_data) -{ - CoglMatrixStack *projection_stack = - _cogl_framebuffer_get_projection_stack (framebuffer); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - CoglMatrixEntry *old_projection_entry, *old_modelview_entry; - - /* NB: This can be called while flushing the journal so we need - * to be very conservative with what state we change. - */ - old_projection_entry = g_steal_pointer (&ctx->current_projection_entry); - old_modelview_entry = g_steal_pointer (&ctx->current_modelview_entry); - - ctx->current_projection_entry = projection_stack->last_entry; - ctx->current_modelview_entry = modelview_entry; - - _cogl_pipeline_flush_gl_state (ctx, ctx->stencil_pipeline, - framebuffer, FALSE, FALSE); - - GE( ctx, glEnable (GL_STENCIL_TEST) ); - - GE( ctx, glColorMask (FALSE, FALSE, FALSE, FALSE) ); - GE( ctx, glDepthMask (FALSE) ); - - if (merge) - { - GE (ctx, glStencilMask (2)); - GE (ctx, glStencilFunc (GL_LEQUAL, 0x2, 0x6)); - } - else - { - /* If we're not using the stencil buffer for clipping then we - don't need to clear the whole stencil buffer, just the area - that will be drawn */ - if (need_clear) - /* If this is being called from the clip stack code then it - will have set up a scissor for the minimum bounding box of - all of the clips. That box will likely mean that this - _cogl_clear won't need to clear the entire - buffer. _cogl_framebuffer_clear_without_flush4f is used instead - of cogl_clear because it won't try to flush the journal */ - _cogl_framebuffer_clear_without_flush4f (framebuffer, - COGL_BUFFER_BIT_STENCIL, - 0, 0, 0, 0); - else - { - /* Just clear the bounding box */ - GE( ctx, glStencilMask (~(GLuint) 0) ); - GE( ctx, glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) ); - _cogl_rectangle_immediate (framebuffer, - ctx->stencil_pipeline, - bounds_x1, bounds_y1, - bounds_x2, bounds_y2); - } - GE (ctx, glStencilMask (1)); - GE (ctx, glStencilFunc (GL_LEQUAL, 0x1, 0x3)); - } - - GE (ctx, glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT)); - - silhouette_callback (framebuffer, ctx->stencil_pipeline, user_data); - - if (merge) - { - /* Now we have the new stencil buffer in bit 1 and the old - stencil buffer in bit 0 so we need to intersect them */ - GE (ctx, glStencilMask (3)); - GE (ctx, glStencilFunc (GL_NEVER, 0x2, 0x3)); - GE (ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR)); - /* Decrement all of the bits twice so that only pixels where the - value is 3 will remain */ - - ctx->current_projection_entry = &ctx->identity_entry; - ctx->current_modelview_entry = &ctx->identity_entry; - - _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline, - -1.0, -1.0, 1.0, 1.0); - _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline, - -1.0, -1.0, 1.0, 1.0); - } - - ctx->current_projection_entry = old_projection_entry; - ctx->current_modelview_entry = old_modelview_entry; - - GE (ctx, glStencilMask (~(GLuint) 0)); - GE (ctx, glDepthMask (TRUE)); - GE (ctx, glColorMask (TRUE, TRUE, TRUE, TRUE)); - - GE (ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1)); - GE (ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP)); -} - -static void -paint_primitive_silhouette (CoglFramebuffer *framebuffer, - CoglPipeline *pipeline, - void *user_data) -{ - _cogl_primitive_draw (user_data, - framebuffer, - pipeline, - COGL_DRAW_SKIP_JOURNAL_FLUSH | - COGL_DRAW_SKIP_PIPELINE_VALIDATION | - COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH); -} - -static void -add_stencil_clip_primitive (CoglFramebuffer *framebuffer, - CoglMatrixEntry *modelview_entry, - CoglPrimitive *primitive, - float bounds_x1, - float bounds_y1, - float bounds_x2, - float bounds_y2, - gboolean merge, - gboolean need_clear) -{ - add_stencil_clip_silhouette (framebuffer, - paint_primitive_silhouette, - modelview_entry, - bounds_x1, - bounds_y1, - bounds_x2, - bounds_y2, - merge, - need_clear, - primitive); -} - -void -_cogl_clip_stack_gl_flush (CoglClipStack *stack, - CoglFramebuffer *framebuffer) -{ - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - gboolean using_stencil_buffer = FALSE; - int scissor_x0; - int scissor_y0; - int scissor_x1; - int scissor_y1; - CoglClipStack *entry; - int scissor_y_start; - - /* If we have already flushed this state then we don't need to do - anything */ - if (ctx->current_clip_stack_valid) - { - if (ctx->current_clip_stack == stack) - return; - - _cogl_clip_stack_unref (ctx->current_clip_stack); - } - - ctx->current_clip_stack_valid = TRUE; - ctx->current_clip_stack = _cogl_clip_stack_ref (stack); - - GE( ctx, glDisable (GL_STENCIL_TEST) ); - - /* If the stack is empty then there's nothing else to do - */ - if (stack == NULL) - { - COGL_NOTE (CLIPPING, "Flushed empty clip stack"); - - GE (ctx, glDisable (GL_SCISSOR_TEST)); - return; - } - - /* Calculate the scissor rect first so that if we eventually have to - clear the stencil buffer then the clear will be clipped to the - intersection of all of the bounding boxes. This saves having to - clear the whole stencil buffer */ - _cogl_clip_stack_get_bounds (stack, - &scissor_x0, &scissor_y0, - &scissor_x1, &scissor_y1); - - /* Enable scissoring as soon as possible */ - if (scissor_x0 >= scissor_x1 || scissor_y0 >= scissor_y1) - scissor_x0 = scissor_y0 = scissor_x1 = scissor_y1 = scissor_y_start = 0; - else - { - /* We store the entry coordinates in Cogl coordinate space - * but OpenGL requires the window origin to be the bottom - * left so we may need to convert the incoming coordinates. - * - * NB: Cogl forces all offscreen rendering to be done upside - * down so in this case no conversion is needed. - */ - - if (cogl_framebuffer_is_y_flipped (framebuffer)) - { - scissor_y_start = scissor_y0; - } - else - { - int framebuffer_height = - cogl_framebuffer_get_height (framebuffer); - - scissor_y_start = framebuffer_height - scissor_y1; - } - } - - COGL_NOTE (CLIPPING, "Flushing scissor to (%i, %i, %i, %i)", - scissor_x0, scissor_y0, - scissor_x1, scissor_y1); - - GE (ctx, glEnable (GL_SCISSOR_TEST)); - GE (ctx, glScissor (scissor_x0, scissor_y_start, - scissor_x1 - scissor_x0, - scissor_y1 - scissor_y0)); - - /* Add all of the entries. This will end up adding them in the - reverse order that they were specified but as all of the clips - are intersecting it should work out the same regardless of the - order */ - for (entry = stack; entry; entry = entry->parent) - { - switch (entry->type) - { - case COGL_CLIP_STACK_PRIMITIVE: - { - CoglClipStackPrimitive *primitive_entry = - (CoglClipStackPrimitive *) entry; - - COGL_NOTE (CLIPPING, "Adding stencil clip for primitive"); - - add_stencil_clip_primitive (framebuffer, - primitive_entry->matrix_entry, - primitive_entry->primitive, - primitive_entry->bounds_x1, - primitive_entry->bounds_y1, - primitive_entry->bounds_x2, - primitive_entry->bounds_y2, - using_stencil_buffer, - TRUE); - - using_stencil_buffer = TRUE; - break; - } - case COGL_CLIP_STACK_RECT: - { - CoglClipStackRect *rect = (CoglClipStackRect *) entry; - - /* We don't need to do anything extra if the clip for this - rectangle was entirely described by its scissor bounds */ - if (!rect->can_be_scissor || - G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_STENCILLING))) - { - COGL_NOTE (CLIPPING, "Adding stencil clip for rectangle"); - - add_stencil_clip_rectangle (framebuffer, - rect->matrix_entry, - rect->x0, - rect->y0, - rect->x1, - rect->y1, - using_stencil_buffer); - using_stencil_buffer = TRUE; - } - break; - } - case COGL_CLIP_STACK_REGION: - { - CoglClipStackRegion *region = (CoglClipStackRegion *) entry; - - /* If nrectangles <= 1, it can be fully represented with the - * scissor clip. - */ - if (cairo_region_num_rectangles (region->region) > 1 || - G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_STENCILLING))) - { - COGL_NOTE (CLIPPING, "Adding stencil clip for region"); - - add_stencil_clip_region (framebuffer, region->region, - using_stencil_buffer); - using_stencil_buffer = TRUE; - } - break; - } - case COGL_CLIP_STACK_WINDOW_RECT: - break; - /* We don't need to do anything for window space rectangles because - * their functionality is entirely implemented by the entry bounding - * box */ - } - } -} diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h b/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h deleted file mode 100644 index 3f3f6b7c8..000000000 --- a/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2008,2009,2010,2011 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Robert Bragg <robert@linux.intel.com> - */ - -#ifndef __COGL_FRAMEBUFFER_GL_PRIVATE_H__ -#define __COGL_FRAMEBUFFER_GL_PRIVATE_H__ - -#include "cogl-attribute-private.h" -#include "cogl-framebuffer-driver.h" -#include "cogl-gl-header.h" - -#define COGL_TYPE_GL_FRAMEBUFFER (cogl_gl_framebuffer_get_type ()) -G_DECLARE_DERIVABLE_TYPE (CoglGlFramebuffer, cogl_gl_framebuffer, - COGL, GL_FRAMEBUFFER, - CoglFramebufferDriver) - -struct _CoglGlFramebufferClass -{ - CoglFramebufferDriverClass parent_class; - - void (* bind) (CoglGlFramebuffer *gl_framebuffer, - GLenum target); - - void (* flush_stereo_mode_state) (CoglGlFramebuffer *gl_framebuffer); -}; - -void -cogl_gl_framebuffer_bind (CoglGlFramebuffer *gl_framebuffer, - GLenum target); - -void -cogl_gl_framebuffer_flush_state_differences (CoglGlFramebuffer *gl_framebuffer, - unsigned long differences); - -#endif /* __COGL_FRAMEBUFFER_GL_PRIVATE_H__ */ - - diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c deleted file mode 100644 index de5ed30d9..000000000 --- a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c +++ /dev/null @@ -1,681 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2007,2008,2009,2012 Intel Corporation. - * Copyright (C) 2018 DisplayLink (UK) Ltd. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - */ - -#include "cogl-config.h" - -#include "cogl-context-private.h" -#include "cogl-framebuffer-private.h" -#include "cogl-framebuffer.h" -#include "cogl-offscreen-private.h" -#include "cogl-texture-private.h" -#include "driver/gl/cogl-util-gl-private.h" -#include "driver/gl/cogl-framebuffer-gl-private.h" -#include "driver/gl/cogl-bitmap-gl-private.h" -#include "driver/gl/cogl-buffer-gl-private.h" - -#include <glib.h> -#include <string.h> - -G_DEFINE_ABSTRACT_TYPE (CoglGlFramebuffer, cogl_gl_framebuffer, - COGL_TYPE_FRAMEBUFFER_DRIVER) - -static CoglContext * -context_from_driver (CoglFramebufferDriver *driver) -{ - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - - return cogl_framebuffer_get_context (framebuffer); -} - -static void -cogl_gl_framebuffer_flush_viewport_state (CoglGlFramebuffer *gl_framebuffer) -{ - CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer); - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - float viewport_x, viewport_y, viewport_width, viewport_height; - float gl_viewport_y; - - cogl_framebuffer_get_viewport4f (framebuffer, - &viewport_x, - &viewport_y, - &viewport_width, - &viewport_height); - - g_return_if_fail (viewport_width >= 0); - g_return_if_fail (viewport_height >= 0); - - /* Convert the Cogl viewport y offset to an OpenGL viewport y offset - * NB: OpenGL defines its window and viewport origins to be bottom - * left, while Cogl defines them to be top left. - */ - if (cogl_framebuffer_is_y_flipped (framebuffer)) - gl_viewport_y = viewport_y; - else - gl_viewport_y = - cogl_framebuffer_get_height (framebuffer) - - (viewport_y + viewport_height); - - COGL_NOTE (OPENGL, "Calling glViewport(%f, %f, %f, %f)", - viewport_x, - gl_viewport_y, - viewport_width, - viewport_height); - - GE (cogl_framebuffer_get_context (framebuffer), - glViewport (viewport_x, - gl_viewport_y, - viewport_width, - viewport_height)); -} - -static void -cogl_gl_framebuffer_flush_clip_state (CoglGlFramebuffer *gl_framebuffer) -{ - CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer); - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - - _cogl_clip_stack_flush (_cogl_framebuffer_get_clip_stack (framebuffer), - framebuffer); -} - -static void -cogl_gl_framebuffer_flush_dither_state (CoglGlFramebuffer *gl_framebuffer) -{ - CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer); - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - gboolean is_dither_enabled; - - is_dither_enabled = cogl_framebuffer_get_dither_enabled (framebuffer); - if (ctx->current_gl_dither_enabled != is_dither_enabled) - { - if (is_dither_enabled) - GE (ctx, glEnable (GL_DITHER)); - else - GE (ctx, glDisable (GL_DITHER)); - ctx->current_gl_dither_enabled = is_dither_enabled; - } -} - -static void -cogl_gl_framebuffer_flush_modelview_state (CoglGlFramebuffer *gl_framebuffer) -{ - CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer); - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - CoglMatrixEntry *modelview_entry = - _cogl_framebuffer_get_modelview_entry (framebuffer); - - _cogl_context_set_current_modelview_entry (ctx, modelview_entry); -} - -static void -cogl_gl_framebuffer_flush_projection_state (CoglGlFramebuffer *gl_framebuffer) -{ - CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer); - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - CoglMatrixEntry *projection_entry = - _cogl_framebuffer_get_projection_entry (framebuffer); - - _cogl_context_set_current_projection_entry (ctx, projection_entry); -} - -static void -cogl_gl_framebuffer_flush_front_face_winding_state (CoglGlFramebuffer *gl_framebuffer) -{ - CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer); - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglContext *context = cogl_framebuffer_get_context (framebuffer); - CoglPipelineCullFaceMode mode; - - /* NB: The face winding state is actually owned by the current - * CoglPipeline. - * - * If we don't have a current pipeline then we can just assume that - * when we later do flush a pipeline we will check the current - * framebuffer to know how to setup the winding */ - if (!context->current_pipeline) - return; - - mode = cogl_pipeline_get_cull_face_mode (context->current_pipeline); - - /* If the current CoglPipeline has a culling mode that doesn't care - * about the winding we can avoid forcing an update of the state and - * bail out. */ - if (mode == COGL_PIPELINE_CULL_FACE_MODE_NONE || - mode == COGL_PIPELINE_CULL_FACE_MODE_BOTH) - return; - - /* Since the winding state is really owned by the current pipeline - * the way we "flush" an updated winding is to dirty the pipeline - * state... */ - context->current_pipeline_changes_since_flush |= - COGL_PIPELINE_STATE_CULL_FACE; - context->current_pipeline_age--; -} - -static void -cogl_gl_framebuffer_flush_stereo_mode_state (CoglGlFramebuffer *gl_framebuffer) -{ - CoglGlFramebufferClass *klass = - COGL_GL_FRAMEBUFFER_GET_CLASS (gl_framebuffer); - - klass->flush_stereo_mode_state (gl_framebuffer); -} - -void -cogl_gl_framebuffer_flush_state_differences (CoglGlFramebuffer *gl_framebuffer, - unsigned long differences) -{ - int bit; - - COGL_FLAGS_FOREACH_START (&differences, 1, bit) - { - /* XXX: We considered having an array of callbacks for each state index - * that we'd call here but decided that this way the compiler is more - * likely going to be able to in-line the flush functions and use the - * index to jump straight to the required code. */ - switch (bit) - { - case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT: - cogl_gl_framebuffer_flush_viewport_state (gl_framebuffer); - break; - case COGL_FRAMEBUFFER_STATE_INDEX_CLIP: - cogl_gl_framebuffer_flush_clip_state (gl_framebuffer); - break; - case COGL_FRAMEBUFFER_STATE_INDEX_DITHER: - cogl_gl_framebuffer_flush_dither_state (gl_framebuffer); - break; - case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW: - cogl_gl_framebuffer_flush_modelview_state (gl_framebuffer); - break; - case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION: - cogl_gl_framebuffer_flush_projection_state (gl_framebuffer); - break; - case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING: - cogl_gl_framebuffer_flush_front_face_winding_state (gl_framebuffer); - break; - case COGL_FRAMEBUFFER_STATE_INDEX_DEPTH_WRITE: - /* Nothing to do for depth write state change; the state will always - * be taken into account when flushing the pipeline's depth state. */ - break; - case COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE: - cogl_gl_framebuffer_flush_stereo_mode_state (gl_framebuffer); - break; - default: - g_warn_if_reached (); - } - } - COGL_FLAGS_FOREACH_END; -} - -void -cogl_gl_framebuffer_bind (CoglGlFramebuffer *gl_framebuffer, - GLenum target) -{ - COGL_GL_FRAMEBUFFER_GET_CLASS (gl_framebuffer)->bind (gl_framebuffer, - target); -} - -static void -cogl_gl_framebuffer_clear (CoglFramebufferDriver *driver, - unsigned long buffers, - float red, - float green, - float blue, - float alpha) -{ - CoglContext *ctx = context_from_driver (driver); - GLbitfield gl_buffers = 0; - - if (buffers & COGL_BUFFER_BIT_COLOR) - { - GE( ctx, glClearColor (red, green, blue, alpha) ); - gl_buffers |= GL_COLOR_BUFFER_BIT; - } - - if (buffers & COGL_BUFFER_BIT_DEPTH) - { - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - gboolean is_depth_writing_enabled; - - gl_buffers |= GL_DEPTH_BUFFER_BIT; - - is_depth_writing_enabled = - cogl_framebuffer_get_depth_write_enabled (framebuffer); - if (ctx->depth_writing_enabled_cache != is_depth_writing_enabled) - { - GE( ctx, glDepthMask (is_depth_writing_enabled)); - - ctx->depth_writing_enabled_cache = is_depth_writing_enabled; - - /* Make sure the DepthMask is updated when the next primitive is drawn */ - ctx->current_pipeline_changes_since_flush |= - COGL_PIPELINE_STATE_DEPTH; - ctx->current_pipeline_age--; - } - } - - if (buffers & COGL_BUFFER_BIT_STENCIL) - gl_buffers |= GL_STENCIL_BUFFER_BIT; - - - GE (ctx, glClear (gl_buffers)); -} - -static void -cogl_gl_framebuffer_finish (CoglFramebufferDriver *driver) -{ - CoglContext *ctx = context_from_driver (driver); - - GE (ctx, glFinish ()); -} - -static void -cogl_gl_framebuffer_flush (CoglFramebufferDriver *driver) -{ - CoglContext *ctx = context_from_driver (driver); - - GE (ctx, glFlush ()); -} - -static void -cogl_gl_framebuffer_draw_attributes (CoglFramebufferDriver *driver, - CoglPipeline *pipeline, - CoglVerticesMode mode, - int first_vertex, - int n_vertices, - CoglAttribute **attributes, - int n_attributes, - CoglDrawFlags flags) -{ - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - - _cogl_flush_attributes_state (framebuffer, pipeline, flags, - attributes, n_attributes); - - GE (cogl_framebuffer_get_context (framebuffer), - glDrawArrays ((GLenum)mode, first_vertex, n_vertices)); -} - -static size_t -sizeof_index_type (CoglIndicesType type) -{ - switch (type) - { - case COGL_INDICES_TYPE_UNSIGNED_BYTE: - return 1; - case COGL_INDICES_TYPE_UNSIGNED_SHORT: - return 2; - case COGL_INDICES_TYPE_UNSIGNED_INT: - return 4; - } - g_return_val_if_reached (0); -} - -static void -cogl_gl_framebuffer_draw_indexed_attributes (CoglFramebufferDriver *driver, - CoglPipeline *pipeline, - CoglVerticesMode mode, - int first_vertex, - int n_vertices, - CoglIndices *indices, - CoglAttribute **attributes, - int n_attributes, - CoglDrawFlags flags) -{ - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglBuffer *buffer; - uint8_t *base; - size_t buffer_offset; - size_t index_size; - GLenum indices_gl_type = 0; - - _cogl_flush_attributes_state (framebuffer, pipeline, flags, - attributes, n_attributes); - - buffer = COGL_BUFFER (cogl_indices_get_buffer (indices)); - - /* Note: we don't try and catch errors with binding the index buffer - * here since OOM errors at this point indicate that nothing has yet - * been uploaded to the indices buffer which we consider to be a - * programmer error. - */ - base = _cogl_buffer_gl_bind (buffer, - COGL_BUFFER_BIND_TARGET_INDEX_BUFFER, NULL); - buffer_offset = cogl_indices_get_offset (indices); - index_size = sizeof_index_type (cogl_indices_get_type (indices)); - - switch (cogl_indices_get_type (indices)) - { - case COGL_INDICES_TYPE_UNSIGNED_BYTE: - indices_gl_type = GL_UNSIGNED_BYTE; - break; - case COGL_INDICES_TYPE_UNSIGNED_SHORT: - indices_gl_type = GL_UNSIGNED_SHORT; - break; - case COGL_INDICES_TYPE_UNSIGNED_INT: - indices_gl_type = GL_UNSIGNED_INT; - break; - } - - GE (cogl_framebuffer_get_context (framebuffer), - glDrawElements ((GLenum)mode, - n_vertices, - indices_gl_type, - base + buffer_offset + index_size * first_vertex)); - - _cogl_buffer_gl_unbind (buffer); -} - -static gboolean -cogl_gl_framebuffer_read_pixels_into_bitmap (CoglFramebufferDriver *driver, - int x, - int y, - CoglReadPixelsFlags source, - CoglBitmap *bitmap, - GError **error) -{ - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - int framebuffer_height = cogl_framebuffer_get_height (framebuffer); - int width = cogl_bitmap_get_width (bitmap); - int height = cogl_bitmap_get_height (bitmap); - CoglPixelFormat format = cogl_bitmap_get_format (bitmap); - CoglPixelFormat internal_format = - cogl_framebuffer_get_internal_format (framebuffer); - CoglPixelFormat required_format; - GLenum gl_intformat; - GLenum gl_format; - GLenum gl_type; - GLenum gl_pack_enum = GL_FALSE; - gboolean pack_invert_set; - int status = FALSE; - - g_return_val_if_fail (cogl_pixel_format_get_n_planes (format) == 1, FALSE); - - cogl_context_flush_framebuffer_state (ctx, - framebuffer, - framebuffer, - COGL_FRAMEBUFFER_STATE_BIND); - - /* The y coordinate should be given in OpenGL's coordinate system - * so 0 is the bottom row. - */ - if (!cogl_framebuffer_is_y_flipped (framebuffer)) - y = framebuffer_height - y - height; - - required_format = ctx->driver_vtable->pixel_format_to_gl (ctx, - format, - &gl_intformat, - &gl_format, - &gl_type); - - if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_MESA_PACK_INVERT) && - (source & COGL_READ_PIXELS_NO_FLIP) == 0 && - !cogl_framebuffer_is_y_flipped (framebuffer)) - { - if (ctx->driver == COGL_DRIVER_GLES2) - gl_pack_enum = GL_PACK_REVERSE_ROW_ORDER_ANGLE; - else - gl_pack_enum = GL_PACK_INVERT_MESA; - - GE (ctx, glPixelStorei (gl_pack_enum, TRUE)); - pack_invert_set = TRUE; - } - else - pack_invert_set = FALSE; - - /* Under GLES only GL_RGBA with GL_UNSIGNED_BYTE as well as an - implementation specific format under - GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES and - GL_IMPLEMENTATION_COLOR_READ_TYPE_OES is supported. We could try - to be more clever and check if the requested type matches that - but we would need some reliable functions to convert from GL - types to Cogl types. For now, lets just always read in - GL_RGBA/GL_UNSIGNED_BYTE and convert if necessary. We also need - to use this intermediate buffer if the rowstride has padding - because GLES does not support setting GL_ROW_LENGTH */ - if ((!_cogl_has_private_feature - (ctx, COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT) && - (gl_format != GL_RGBA || gl_type != GL_UNSIGNED_BYTE || - cogl_bitmap_get_rowstride (bitmap) != 4 * width)) || - (required_format & ~COGL_PREMULT_BIT) != (format & ~COGL_PREMULT_BIT)) - { - CoglBitmap *tmp_bmp; - CoglPixelFormat read_format; - int bpp, rowstride; - uint8_t *tmp_data; - gboolean succeeded; - - if (_cogl_has_private_feature - (ctx, COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT)) - read_format = required_format; - else - { - read_format = COGL_PIXEL_FORMAT_RGBA_8888; - gl_format = GL_RGBA; - gl_type = GL_UNSIGNED_BYTE; - } - - if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (read_format)) - { - read_format = ((read_format & ~COGL_PREMULT_BIT) | - (internal_format & COGL_PREMULT_BIT)); - } - - tmp_bmp = _cogl_bitmap_new_with_malloc_buffer (ctx, - width, height, - read_format, - error); - if (!tmp_bmp) - goto EXIT; - - bpp = cogl_pixel_format_get_bytes_per_pixel (read_format, 0); - rowstride = cogl_bitmap_get_rowstride (tmp_bmp); - - ctx->texture_driver->prep_gl_for_pixels_download (ctx, - rowstride, - width, - bpp); - - /* Note: we don't worry about catching errors here since we know - * we won't be lazily allocating storage for this buffer so it - * won't fail due to lack of memory. */ - tmp_data = _cogl_bitmap_gl_bind (tmp_bmp, - COGL_BUFFER_ACCESS_WRITE, - COGL_BUFFER_MAP_HINT_DISCARD, - NULL); - - GE( ctx, glReadPixels (x, y, width, height, - gl_format, gl_type, - tmp_data) ); - - _cogl_bitmap_gl_unbind (tmp_bmp); - - succeeded = _cogl_bitmap_convert_into_bitmap (tmp_bmp, bitmap, error); - - cogl_object_unref (tmp_bmp); - - if (!succeeded) - goto EXIT; - } - else - { - CoglBitmap *shared_bmp; - CoglPixelFormat bmp_format; - int bpp, rowstride; - gboolean succeeded = FALSE; - uint8_t *pixels; - GError *internal_error = NULL; - - rowstride = cogl_bitmap_get_rowstride (bitmap); - - /* We match the premultiplied state of the target buffer to the - * premultiplied state of the framebuffer so that it will get - * converted to the right format below */ - if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (format)) - bmp_format = ((format & ~COGL_PREMULT_BIT) | - (internal_format & COGL_PREMULT_BIT)); - else - bmp_format = format; - - if (bmp_format != format) - shared_bmp = _cogl_bitmap_new_shared (bitmap, - bmp_format, - width, height, - rowstride); - else - shared_bmp = cogl_object_ref (bitmap); - - bpp = cogl_pixel_format_get_bytes_per_pixel (bmp_format, 0); - - ctx->texture_driver->prep_gl_for_pixels_download (ctx, - rowstride, - width, - bpp); - - pixels = _cogl_bitmap_gl_bind (shared_bmp, - COGL_BUFFER_ACCESS_WRITE, - 0, /* hints */ - &internal_error); - /* NB: _cogl_bitmap_gl_bind() can return NULL in successful - * cases so we have to explicitly check the cogl error pointer - * to know if there was a problem */ - if (internal_error) - { - cogl_object_unref (shared_bmp); - g_propagate_error (error, internal_error); - goto EXIT; - } - - GE( ctx, glReadPixels (x, y, - width, height, - gl_format, gl_type, - pixels) ); - - _cogl_bitmap_gl_unbind (shared_bmp); - - /* Convert to the premult format specified by the caller - in-place. This will do nothing if the premult status is already - correct. */ - if (_cogl_bitmap_convert_premult_status (shared_bmp, format, error)) - succeeded = TRUE; - - cogl_object_unref (shared_bmp); - - if (!succeeded) - goto EXIT; - } - - if (!cogl_framebuffer_is_y_flipped (framebuffer) && - (source & COGL_READ_PIXELS_NO_FLIP) == 0 && - !pack_invert_set) - { - uint8_t *temprow; - int rowstride; - uint8_t *pixels; - - rowstride = cogl_bitmap_get_rowstride (bitmap); - pixels = _cogl_bitmap_map (bitmap, - COGL_BUFFER_ACCESS_READ | - COGL_BUFFER_ACCESS_WRITE, - 0, /* hints */ - error); - - if (pixels == NULL) - goto EXIT; - - temprow = g_alloca (rowstride * sizeof (uint8_t)); - - /* vertically flip the buffer in-place */ - for (y = 0; y < height / 2; y++) - { - if (y != height - y - 1) /* skip center row */ - { - memcpy (temprow, - pixels + y * rowstride, rowstride); - memcpy (pixels + y * rowstride, - pixels + (height - y - 1) * rowstride, rowstride); - memcpy (pixels + (height - y - 1) * rowstride, - temprow, - rowstride); - } - } - - _cogl_bitmap_unmap (bitmap); - } - - status = TRUE; - -EXIT: - - /* Currently this function owns the pack_invert state and we don't want this - * to interfere with other Cogl components so all other code can assume that - * we leave the pack_invert state off. */ - if (pack_invert_set) - GE (ctx, glPixelStorei (gl_pack_enum, FALSE)); - - return status; -} - -static void -cogl_gl_framebuffer_init (CoglGlFramebuffer *gl_framebuffer) -{ -} - -static void -cogl_gl_framebuffer_class_init (CoglGlFramebufferClass *klass) -{ - CoglFramebufferDriverClass *driver_class = - COGL_FRAMEBUFFER_DRIVER_CLASS (klass); - - driver_class->clear = cogl_gl_framebuffer_clear; - driver_class->finish = cogl_gl_framebuffer_finish; - driver_class->flush = cogl_gl_framebuffer_flush; - driver_class->draw_attributes = cogl_gl_framebuffer_draw_attributes; - driver_class->draw_indexed_attributes = - cogl_gl_framebuffer_draw_indexed_attributes; - driver_class->read_pixels_into_bitmap = - cogl_gl_framebuffer_read_pixels_into_bitmap; -} diff --git a/cogl/cogl/driver/gl/cogl-gl-framebuffer-back.c b/cogl/cogl/driver/gl/cogl-gl-framebuffer-back.c deleted file mode 100644 index d6609bb20..000000000 --- a/cogl/cogl/driver/gl/cogl-gl-framebuffer-back.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (C) 2007,2008,2009,2012 Intel Corporation. - * Copyright (C) 2018 DisplayLink (UK) Ltd. - * Copyright (C) 2020 Red Hat - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include "cogl-config.h" - -#include "driver/gl/cogl-gl-framebuffer-back.h" - -#include <gio/gio.h> - -#include "cogl-context-private.h" -#include "cogl-framebuffer-private.h" -#include "cogl-offscreen-private.h" -#include "driver/gl/cogl-util-gl-private.h" - -struct _CoglGlFramebufferBack -{ - CoglGlFramebuffer parent; - - gboolean dirty_bitmasks; - CoglFramebufferBits bits; -}; - -G_DEFINE_TYPE (CoglGlFramebufferBack, cogl_gl_framebuffer_back, - COGL_TYPE_GL_FRAMEBUFFER) - -static gboolean -ensure_bits_initialized (CoglGlFramebufferBack *gl_framebuffer_back) -{ - CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_back); - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - CoglFramebufferBits *bits = &gl_framebuffer_back->bits; - g_autoptr (GError) error = NULL; - - if (!gl_framebuffer_back->dirty_bitmasks) - return TRUE; - - cogl_context_flush_framebuffer_state (ctx, - framebuffer, - framebuffer, - COGL_FRAMEBUFFER_STATE_BIND); - -#ifdef HAVE_COGL_GL - if (ctx->driver == COGL_DRIVER_GL3) - { - const struct { - GLenum attachment, pname; - size_t offset; - } params[] = { - { - .attachment = GL_BACK_LEFT, - .pname = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, - .offset = offsetof (CoglFramebufferBits, red), - }, - { - .attachment = GL_BACK_LEFT, - .pname = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, - .offset = offsetof (CoglFramebufferBits, green), - }, - { - .attachment = GL_BACK_LEFT, - .pname = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, - .offset = offsetof (CoglFramebufferBits, blue), - }, - { - .attachment = GL_BACK_LEFT, - .pname = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, - .offset = offsetof (CoglFramebufferBits, alpha), - }, - { - .attachment = GL_DEPTH, - .pname = GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, - .offset = offsetof (CoglFramebufferBits, depth), - }, - { - .attachment = GL_STENCIL, - .pname = GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, - .offset = offsetof (CoglFramebufferBits, stencil), - }, - }; - int i; - - for (i = 0; i < G_N_ELEMENTS (params); i++) - { - int *value = - (int *) ((uint8_t *) bits + params[i].offset); - - GE (ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, - params[i].attachment, - params[i].pname, - value)); - } - } - else -#endif /* HAVE_COGL_GL */ - { - GE (ctx, glGetIntegerv (GL_RED_BITS, &bits->red)); - GE (ctx, glGetIntegerv (GL_GREEN_BITS, &bits->green)); - GE (ctx, glGetIntegerv (GL_BLUE_BITS, &bits->blue)); - GE (ctx, glGetIntegerv (GL_ALPHA_BITS, &bits->alpha)); - GE (ctx, glGetIntegerv (GL_DEPTH_BITS, &bits->depth)); - GE (ctx, glGetIntegerv (GL_STENCIL_BITS, &bits->stencil)); - } - - COGL_NOTE (FRAMEBUFFER, - "RGBA/D/S Bits for framebuffer[%p, %s]: %d, %d, %d, %d, %d, %d", - framebuffer, - G_OBJECT_TYPE_NAME (framebuffer), - bits->red, - bits->blue, - bits->green, - bits->alpha, - bits->depth, - bits->stencil); - - gl_framebuffer_back->dirty_bitmasks = FALSE; - - return TRUE; -} - -static void -cogl_gl_framebuffer_back_query_bits (CoglFramebufferDriver *driver, - CoglFramebufferBits *bits) -{ - CoglGlFramebufferBack *gl_framebuffer_back = COGL_GL_FRAMEBUFFER_BACK (driver); - - if (!ensure_bits_initialized (gl_framebuffer_back)) - return; - - *bits = gl_framebuffer_back->bits; -} - -static void -cogl_gl_framebuffer_back_discard_buffers (CoglFramebufferDriver *driver, - unsigned long buffers) -{ - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - GLenum attachments[3]; - int i = 0; - - if (!ctx->glDiscardFramebuffer) - return; - - if (buffers & COGL_BUFFER_BIT_COLOR) - attachments[i++] = GL_COLOR; - if (buffers & COGL_BUFFER_BIT_DEPTH) - attachments[i++] = GL_DEPTH; - if (buffers & COGL_BUFFER_BIT_STENCIL) - attachments[i++] = GL_STENCIL; - - cogl_context_flush_framebuffer_state (ctx, - framebuffer, - framebuffer, - COGL_FRAMEBUFFER_STATE_BIND); - GE (ctx, glDiscardFramebuffer (GL_FRAMEBUFFER, i, attachments)); -} - -static void -cogl_gl_framebuffer_back_bind (CoglGlFramebuffer *gl_framebuffer, - GLenum target) -{ - CoglGlFramebufferBack *gl_framebuffer_back = - COGL_GL_FRAMEBUFFER_BACK (gl_framebuffer); - CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_back); - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - - cogl_onscreen_bind (COGL_ONSCREEN (framebuffer)); - - GE (ctx, glBindFramebuffer (target, 0)); - - /* Initialise the glDrawBuffer state the first time the context - * is bound to the default framebuffer. If the winsys is using a - * surfaceless context for the initial make current then the - * default draw buffer will be GL_NONE so we need to correct - * that. We can't do it any earlier because binding GL_BACK when - * there is no default framebuffer won't work */ - if (!ctx->was_bound_to_onscreen) - { - if (ctx->glDrawBuffer) - { - GE (ctx, glDrawBuffer (GL_BACK)); - } - else if (ctx->glDrawBuffers) - { - /* glDrawBuffer isn't available on GLES 3.0 so we need - * to be able to use glDrawBuffers as well. On GLES 2 - * neither is available but the state should always be - * GL_BACK anyway so we don't need to set anything. On - * desktop GL this must be GL_BACK_LEFT instead of - * GL_BACK but as this code path will only be hit for - * GLES we can just use GL_BACK. */ - static const GLenum buffers[] = { GL_BACK }; - - GE (ctx, glDrawBuffers (G_N_ELEMENTS (buffers), buffers)); - } - - ctx->was_bound_to_onscreen = TRUE; - } -} - -static void -cogl_gl_framebuffer_back_flush_stereo_mode_state (CoglGlFramebuffer *gl_framebuffer) -{ - CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer); - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - GLenum draw_buffer = GL_BACK; - - if (!ctx->glDrawBuffer) - return; - - /* The one-shot default draw buffer setting in _cogl_framebuffer_gl_bind - * must have already happened. If not it would override what we set here. */ - g_assert (ctx->was_bound_to_onscreen); - - switch (cogl_framebuffer_get_stereo_mode (framebuffer)) - { - case COGL_STEREO_BOTH: - draw_buffer = GL_BACK; - break; - case COGL_STEREO_LEFT: - draw_buffer = GL_BACK_LEFT; - break; - case COGL_STEREO_RIGHT: - draw_buffer = GL_BACK_RIGHT; - break; - } - - if (ctx->current_gl_draw_buffer != draw_buffer) - { - GE (ctx, glDrawBuffer (draw_buffer)); - ctx->current_gl_draw_buffer = draw_buffer; - } -} - -CoglGlFramebufferBack * -cogl_gl_framebuffer_back_new (CoglFramebuffer *framebuffer, - const CoglFramebufferDriverConfig *driver_config, - GError **error) -{ - if (!COGL_IS_ONSCREEN (framebuffer)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Incompatible framebuffer"); - return NULL; - } - - return g_object_new (COGL_TYPE_GL_FRAMEBUFFER_BACK, - "framebuffer", framebuffer, - NULL); -} - -static void -cogl_gl_framebuffer_back_init (CoglGlFramebufferBack *gl_framebuffer_back) -{ - gl_framebuffer_back->dirty_bitmasks = TRUE; -} - -static void -cogl_gl_framebuffer_back_class_init (CoglGlFramebufferBackClass *klass) -{ - CoglFramebufferDriverClass *driver_class = - COGL_FRAMEBUFFER_DRIVER_CLASS (klass); - CoglGlFramebufferClass *gl_framebuffer_class = - COGL_GL_FRAMEBUFFER_CLASS (klass); - - driver_class->query_bits = cogl_gl_framebuffer_back_query_bits; - driver_class->discard_buffers = cogl_gl_framebuffer_back_discard_buffers; - - gl_framebuffer_class->bind = cogl_gl_framebuffer_back_bind; - gl_framebuffer_class->flush_stereo_mode_state = - cogl_gl_framebuffer_back_flush_stereo_mode_state; -} diff --git a/cogl/cogl/driver/gl/cogl-gl-framebuffer-back.h b/cogl/cogl/driver/gl/cogl-gl-framebuffer-back.h deleted file mode 100644 index 417f8a738..000000000 --- a/cogl/cogl/driver/gl/cogl-gl-framebuffer-back.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2020 Red Hat - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#ifndef COGL_GL_FRAMEBUFFER_BACK_H -#define COGL_GL_FRAMEBUFFER_BACK_H - -#include "cogl-framebuffer-gl-private.h" - -#define COGL_TYPE_GL_FRAMEBUFFER_BACK (cogl_gl_framebuffer_back_get_type ()) -G_DECLARE_FINAL_TYPE (CoglGlFramebufferBack, cogl_gl_framebuffer_back, - COGL, GL_FRAMEBUFFER_BACK, - CoglGlFramebuffer) - -CoglGlFramebufferBack * -cogl_gl_framebuffer_back_new (CoglFramebuffer *framebuffer, - const CoglFramebufferDriverConfig *driver_config, - GError **error); - -#endif /* COGL_GL_FRAMEBUFFER_BACK_H */ diff --git a/cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.c b/cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.c deleted file mode 100644 index c8db6a23a..000000000 --- a/cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.c +++ /dev/null @@ -1,659 +0,0 @@ -/* - * Copyright (C) 2007,2008,2009,2012 Intel Corporation. - * Copyright (C) 2018 DisplayLink (UK) Ltd. - * Copyright (C) 2020 Red Hat - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include "cogl-config.h" - -#include "driver/gl/cogl-gl-framebuffer-fbo.h" - -#include <gio/gio.h> - -#include "cogl-context-private.h" -#include "cogl-framebuffer-private.h" -#include "cogl-offscreen-private.h" -#include "driver/gl/cogl-texture-gl-private.h" -#include "driver/gl/cogl-util-gl-private.h" - -typedef struct _CoglGlFbo -{ - GLuint fbo_handle; - GList *renderbuffers; - int samples_per_pixel; -} CoglGlFbo; - -struct _CoglGlFramebufferFbo -{ - CoglGlFramebuffer parent; - - CoglGlFbo gl_fbo; - - gboolean dirty_bitmasks; - CoglFramebufferBits bits; -}; - -G_DEFINE_TYPE (CoglGlFramebufferFbo, cogl_gl_framebuffer_fbo, - COGL_TYPE_GL_FRAMEBUFFER) - -static gboolean -ensure_bits_initialized (CoglGlFramebufferFbo *gl_framebuffer_fbo) -{ - CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_fbo); - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - CoglFramebufferBits *bits = &gl_framebuffer_fbo->bits; - g_autoptr (GError) error = NULL; - - if (!gl_framebuffer_fbo->dirty_bitmasks) - return TRUE; - - cogl_context_flush_framebuffer_state (ctx, - framebuffer, - framebuffer, - COGL_FRAMEBUFFER_STATE_BIND); - -#ifdef HAVE_COGL_GL - if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS)) - { - const struct { - GLenum attachment, pname; - size_t offset; - } params[] = { - { - .attachment = GL_COLOR_ATTACHMENT0, - .pname = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, - .offset = offsetof (CoglFramebufferBits, red), - }, - { - .attachment = GL_COLOR_ATTACHMENT0, - .pname = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, - .offset = offsetof (CoglFramebufferBits, green), - }, - { - .attachment = GL_COLOR_ATTACHMENT0, - .pname = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, - .offset = offsetof (CoglFramebufferBits, blue), - }, - { - .attachment = GL_COLOR_ATTACHMENT0, - .pname = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, - .offset = offsetof (CoglFramebufferBits, alpha), - }, - { - .attachment = GL_DEPTH_ATTACHMENT, - .pname = GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, - .offset = offsetof (CoglFramebufferBits, depth), - }, - { - .attachment = GL_STENCIL_ATTACHMENT, - .pname = GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, - .offset = offsetof (CoglFramebufferBits, stencil), - }, - }; - int i; - - for (i = 0; i < G_N_ELEMENTS (params); i++) - { - int *value = - (int *) ((uint8_t *) bits + params[i].offset); - - GE (ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, - params[i].attachment, - params[i].pname, - value)); - } - } - else -#endif /* HAVE_COGL_GL */ - { - GE (ctx, glGetIntegerv (GL_RED_BITS, &bits->red)); - GE (ctx, glGetIntegerv (GL_GREEN_BITS, &bits->green)); - GE (ctx, glGetIntegerv (GL_BLUE_BITS, &bits->blue)); - GE (ctx, glGetIntegerv (GL_ALPHA_BITS, &bits->alpha)); - GE (ctx, glGetIntegerv (GL_DEPTH_BITS, &bits->depth)); - GE (ctx, glGetIntegerv (GL_STENCIL_BITS, &bits->stencil)); - } - - if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) && - (cogl_framebuffer_get_internal_format (framebuffer) == - COGL_PIXEL_FORMAT_A_8)) - { - bits->alpha = bits->red; - bits->red = 0; - } - - COGL_NOTE (FRAMEBUFFER, - "RGBA/D/S Bits for framebuffer[%p, %s]: %d, %d, %d, %d, %d, %d", - framebuffer, - G_OBJECT_TYPE_NAME (framebuffer), - bits->red, - bits->blue, - bits->green, - bits->alpha, - bits->depth, - bits->stencil); - - gl_framebuffer_fbo->dirty_bitmasks = FALSE; - - return TRUE; -} - -static void -cogl_gl_framebuffer_fbo_query_bits (CoglFramebufferDriver *driver, - CoglFramebufferBits *bits) -{ - CoglGlFramebufferFbo *gl_framebuffer_fbo = COGL_GL_FRAMEBUFFER_FBO (driver); - - if (!ensure_bits_initialized (gl_framebuffer_fbo)) - return; - - *bits = gl_framebuffer_fbo->bits; -} - -static void -cogl_gl_framebuffer_fbo_discard_buffers (CoglFramebufferDriver *driver, - unsigned long buffers) -{ - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - GLenum attachments[3]; - int i = 0; - - if (!ctx->glDiscardFramebuffer) - return; - - if (buffers & COGL_BUFFER_BIT_COLOR) - attachments[i++] = GL_COLOR_ATTACHMENT0; - if (buffers & COGL_BUFFER_BIT_DEPTH) - attachments[i++] = GL_DEPTH_ATTACHMENT; - if (buffers & COGL_BUFFER_BIT_STENCIL) - attachments[i++] = GL_STENCIL_ATTACHMENT; - - cogl_context_flush_framebuffer_state (ctx, - framebuffer, - framebuffer, - COGL_FRAMEBUFFER_STATE_BIND); - GE (ctx, glDiscardFramebuffer (GL_FRAMEBUFFER, i, attachments)); -} - -static void -cogl_gl_framebuffer_fbo_bind (CoglGlFramebuffer *gl_framebuffer, - GLenum target) -{ - CoglGlFramebufferFbo *gl_framebuffer_fbo = - COGL_GL_FRAMEBUFFER_FBO (gl_framebuffer); - CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_fbo); - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - - GE (ctx, glBindFramebuffer (target, gl_framebuffer_fbo->gl_fbo.fbo_handle)); -} - -static void -cogl_gl_framebuffer_fbo_flush_stereo_mode_state (CoglGlFramebuffer *gl_framebuffer) -{ - CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer); - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - - switch (cogl_framebuffer_get_stereo_mode (framebuffer)) - { - case COGL_STEREO_BOTH: - break; - case COGL_STEREO_LEFT: - case COGL_STEREO_RIGHT: - g_warn_if_reached (); - break; - } -} - -static GList * -try_creating_renderbuffers (CoglContext *ctx, - int width, - int height, - CoglOffscreenAllocateFlags flags, - int n_samples) -{ - GList *renderbuffers = NULL; - GLuint gl_depth_stencil_handle; - - if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL) - { - GLenum format; - - /* WebGL adds a GL_DEPTH_STENCIL_ATTACHMENT and requires that we - * use the GL_DEPTH_STENCIL format. */ - /* Although GL_OES_packed_depth_stencil is mostly equivalent to - * GL_EXT_packed_depth_stencil, one notable difference is that - * GL_OES_packed_depth_stencil doesn't allow GL_DEPTH_STENCIL to - * be passed as an internal format to glRenderbufferStorage. - */ - if (_cogl_has_private_feature - (ctx, COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL)) - format = GL_DEPTH_STENCIL; - else - { - g_return_val_if_fail ( - _cogl_has_private_feature (ctx, - COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL), - NULL); - format = GL_DEPTH24_STENCIL8; - } - - /* Create a renderbuffer for depth and stenciling */ - GE (ctx, glGenRenderbuffers (1, &gl_depth_stencil_handle)); - GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_stencil_handle)); - if (n_samples) - GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER, - n_samples, - format, - width, height)); - else - GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, format, - width, height)); - GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0)); - - - GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, - GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, - gl_depth_stencil_handle)); - GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, - gl_depth_stencil_handle)); - renderbuffers = - g_list_prepend (renderbuffers, - GUINT_TO_POINTER (gl_depth_stencil_handle)); - } - - if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH) - { - GLuint gl_depth_handle; - - GE (ctx, glGenRenderbuffers (1, &gl_depth_handle)); - GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_handle)); - /* For now we just ask for GL_DEPTH_COMPONENT16 since this is all that's - * available under GLES */ - if (n_samples) - GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER, - n_samples, - GL_DEPTH_COMPONENT16, - width, height)); - else - GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, - width, height)); - GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0)); - GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, gl_depth_handle)); - renderbuffers = - g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_depth_handle)); - } - - if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL) - { - GLuint gl_stencil_handle; - - GE (ctx, glGenRenderbuffers (1, &gl_stencil_handle)); - GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle)); - if (n_samples) - GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER, - n_samples, - GL_STENCIL_INDEX8, - width, height)); - else - GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8, - width, height)); - GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0)); - GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER, - GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, gl_stencil_handle)); - renderbuffers = - g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_stencil_handle)); - } - - return renderbuffers; -} - -static void -delete_renderbuffers (CoglContext *ctx, - GList *renderbuffers) -{ - GList *l; - - for (l = renderbuffers; l; l = l->next) - { - GLuint renderbuffer = GPOINTER_TO_UINT (l->data); - GE (ctx, glDeleteRenderbuffers (1, &renderbuffer)); - } - - g_list_free (renderbuffers); -} - -/* - * NB: This function may be called with a standalone GLES2 context - * bound so we can create a shadow framebuffer that wraps the same - * CoglTexture as the given CoglOffscreen. This function shouldn't - * modify anything in - */ -static gboolean -try_creating_fbo (CoglContext *ctx, - CoglTexture *texture, - int texture_level, - int texture_level_width, - int texture_level_height, - const CoglFramebufferConfig *config, - CoglOffscreenAllocateFlags flags, - CoglGlFbo *gl_fbo) -{ - GLuint tex_gl_handle; - GLenum tex_gl_target; - GLenum status; - int n_samples; - - if (!cogl_texture_get_gl_texture (texture, &tex_gl_handle, &tex_gl_target)) - return FALSE; - - if (tex_gl_target != GL_TEXTURE_2D -#ifdef HAVE_COGL_GL - && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB -#endif - ) - return FALSE; - - if (config->samples_per_pixel) - { - if (!ctx->glFramebufferTexture2DMultisampleIMG) - return FALSE; - n_samples = config->samples_per_pixel; - } - else - n_samples = 0; - - /* We are about to generate and bind a new fbo, so we pretend to - * change framebuffer state so that the old framebuffer will be - * rebound again before drawing. */ - ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND; - - /* Generate framebuffer */ - ctx->glGenFramebuffers (1, &gl_fbo->fbo_handle); - GE (ctx, glBindFramebuffer (GL_FRAMEBUFFER, gl_fbo->fbo_handle)); - - if (n_samples) - { - GE (ctx, glFramebufferTexture2DMultisampleIMG (GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - tex_gl_target, tex_gl_handle, - n_samples, - texture_level)); - } - else - GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - tex_gl_target, tex_gl_handle, - texture_level)); - - if (flags) - { - gl_fbo->renderbuffers = - try_creating_renderbuffers (ctx, - texture_level_width, - texture_level_height, - flags, - n_samples); - } - - /* Make sure it's complete */ - status = ctx->glCheckFramebufferStatus (GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) - { - GE (ctx, glDeleteFramebuffers (1, &gl_fbo->fbo_handle)); - - delete_renderbuffers (ctx, gl_fbo->renderbuffers); - gl_fbo->renderbuffers = NULL; - - return FALSE; - } - - /* Update the real number of samples_per_pixel now that we have a - * complete framebuffer */ - if (n_samples) - { - GLenum attachment = GL_COLOR_ATTACHMENT0; - GLenum pname = GL_TEXTURE_SAMPLES_IMG; - int texture_samples; - - GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, - attachment, - pname, - &texture_samples) ); - gl_fbo->samples_per_pixel = texture_samples; - } - - return TRUE; -} - -CoglGlFramebufferFbo * -cogl_gl_framebuffer_fbo_new (CoglFramebuffer *framebuffer, - const CoglFramebufferDriverConfig *driver_config, - GError **error) -{ - CoglContext *context = cogl_framebuffer_get_context (framebuffer); - CoglOffscreen *offscreen; - CoglTexture *texture; - int texture_level; - int level_width; - int level_height; - const CoglFramebufferConfig *config; - CoglGlFbo *gl_fbo; - CoglGlFramebufferFbo *gl_framebuffer_fbo; - CoglOffscreenAllocateFlags allocate_flags; - - if (!COGL_IS_OFFSCREEN (framebuffer)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Incompatible framebuffer"); - return NULL; - } - - offscreen = COGL_OFFSCREEN (framebuffer); - texture = cogl_offscreen_get_texture (offscreen); - texture_level = cogl_offscreen_get_texture_level (offscreen); - - g_return_val_if_fail (texture_level < _cogl_texture_get_n_levels (texture), - NULL); - - _cogl_texture_get_level_size (texture, - texture_level, - &level_width, - &level_height, - NULL); - - /* XXX: The framebuffer_object spec isn't clear in defining whether attaching - * a texture as a renderbuffer with mipmap filtering enabled while the - * mipmaps have not been uploaded should result in an incomplete framebuffer - * object. (different drivers make different decisions) - * - * To avoid an error with drivers that do consider this a problem we - * explicitly set non mipmapped filters here. These will later be reset when - * the texture is actually used for rendering according to the filters set on - * the corresponding CoglPipeline. - */ - _cogl_texture_gl_flush_legacy_texobj_filters (texture, - GL_NEAREST, GL_NEAREST); - - config = cogl_framebuffer_get_config (framebuffer); - - gl_framebuffer_fbo = g_object_new (COGL_TYPE_GL_FRAMEBUFFER_FBO, - "framebuffer", framebuffer, - NULL); - gl_fbo = &gl_framebuffer_fbo->gl_fbo; - - if ((driver_config->disable_depth_and_stencil && - try_creating_fbo (context, - texture, - texture_level, - level_width, - level_height, - config, - allocate_flags = 0, - gl_fbo)) || - - (context->have_last_offscreen_allocate_flags && - try_creating_fbo (context, - texture, - texture_level, - level_width, - level_height, - config, - allocate_flags = context->last_offscreen_allocate_flags, - gl_fbo)) || - - ( - /* NB: WebGL introduces a DEPTH_STENCIL_ATTACHMENT and doesn't - * need an extension to handle _FLAG_DEPTH_STENCIL */ - (_cogl_has_private_feature - (context, COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) || - _cogl_has_private_feature - (context, COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL)) && - try_creating_fbo (context, - texture, - texture_level, - level_width, - level_height, - config, - allocate_flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL, - gl_fbo)) || - - try_creating_fbo (context, - texture, - texture_level, - level_width, - level_height, - config, - allocate_flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH | - COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL, - gl_fbo) || - - try_creating_fbo (context, - texture, - texture_level, - level_width, - level_height, - config, - allocate_flags = COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL, - gl_fbo) || - - try_creating_fbo (context, - texture, - texture_level, - level_width, - level_height, - config, - allocate_flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH, - gl_fbo) || - - try_creating_fbo (context, - texture, - texture_level, - level_width, - level_height, - config, - allocate_flags = 0, - gl_fbo)) - { - cogl_framebuffer_update_samples_per_pixel (framebuffer, - gl_fbo->samples_per_pixel); - - if (!driver_config->disable_depth_and_stencil) - { - /* Record that the last set of flags succeeded so that we can - try that set first next time */ - context->last_offscreen_allocate_flags = allocate_flags; - context->have_last_offscreen_allocate_flags = TRUE; - } - - return gl_framebuffer_fbo; - } - else - { - g_object_unref (gl_framebuffer_fbo); - g_set_error (error, COGL_FRAMEBUFFER_ERROR, - COGL_FRAMEBUFFER_ERROR_ALLOCATE, - "Failed to create an OpenGL framebuffer object"); - return NULL; - } -} - -static void -cogl_gl_framebuffer_fbo_dispose (GObject *object) -{ - CoglGlFramebufferFbo *gl_framebuffer_fbo = COGL_GL_FRAMEBUFFER_FBO (object); - CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_fbo); - CoglFramebuffer *framebuffer = - cogl_framebuffer_driver_get_framebuffer (driver); - CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); - - delete_renderbuffers (ctx, gl_framebuffer_fbo->gl_fbo.renderbuffers); - gl_framebuffer_fbo->gl_fbo.renderbuffers = NULL; - - if (gl_framebuffer_fbo->gl_fbo.fbo_handle) - { - GE (ctx, glDeleteFramebuffers (1, - &gl_framebuffer_fbo->gl_fbo.fbo_handle)); - gl_framebuffer_fbo->gl_fbo.fbo_handle = 0; - } - - G_OBJECT_CLASS (cogl_gl_framebuffer_fbo_parent_class)->dispose (object); -} - -static void -cogl_gl_framebuffer_fbo_init (CoglGlFramebufferFbo *gl_framebuffer_fbo) -{ - gl_framebuffer_fbo->dirty_bitmasks = TRUE; -} - -static void -cogl_gl_framebuffer_fbo_class_init (CoglGlFramebufferFboClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - CoglFramebufferDriverClass *driver_class = - COGL_FRAMEBUFFER_DRIVER_CLASS (klass); - CoglGlFramebufferClass *gl_framebuffer_class = - COGL_GL_FRAMEBUFFER_CLASS (klass); - - object_class->dispose = cogl_gl_framebuffer_fbo_dispose; - - driver_class->query_bits = cogl_gl_framebuffer_fbo_query_bits; - driver_class->discard_buffers = cogl_gl_framebuffer_fbo_discard_buffers; - - gl_framebuffer_class->bind = cogl_gl_framebuffer_fbo_bind; - gl_framebuffer_class->flush_stereo_mode_state = - cogl_gl_framebuffer_fbo_flush_stereo_mode_state; -} diff --git a/cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.h b/cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.h deleted file mode 100644 index 896847cf8..000000000 --- a/cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2020 Red Hat - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#ifndef COGL_GL_FRAMEBUFFER_FBO_H -#define COGL_GL_FRAMEBUFFER_FBO_H - -#include "driver/gl/cogl-framebuffer-gl-private.h" - -#define COGL_TYPE_GL_FRAMEBUFFER_FBO (cogl_gl_framebuffer_fbo_get_type ()) -G_DECLARE_FINAL_TYPE (CoglGlFramebufferFbo, cogl_gl_framebuffer_fbo, - COGL, GL_FRAMEBUFFER_FBO, - CoglGlFramebuffer) - -CoglGlFramebufferFbo * -cogl_gl_framebuffer_fbo_new (CoglFramebuffer *framebuffer, - const CoglFramebufferDriverConfig *driver_config, - GError **error); - -#endif /* COGL_GL_FRAMEBUFFER_FBO_H */ diff --git a/cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl-private.h b/cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl-private.h deleted file mode 100644 index 72f5928a8..000000000 --- a/cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl-private.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2010 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Robert Bragg <robert@linux.intel.com> - */ - -#ifndef __COGL_PIPELINE_FRAGEND_GLSL_PRIVATE_H -#define __COGL_PIPELINE_FRAGEND_GLSL_PRIVATE_H - -#include "cogl-pipeline-private.h" - -extern const CoglPipelineFragend _cogl_pipeline_glsl_fragend; - -GLuint -_cogl_pipeline_fragend_glsl_get_shader (CoglPipeline *pipeline); - -#endif /* __COGL_PIPELINE_FRAGEND_GLSL_PRIVATE_H */ - diff --git a/cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl.c b/cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl.c deleted file mode 100644 index d932a5cf5..000000000 --- a/cogl/cogl/driver/gl/cogl-pipeline-fragend-glsl.c +++ /dev/null @@ -1,1120 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2008,2009,2010,2013 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Robert Bragg <robert@linux.intel.com> - * Neil Roberts <neil@linux.intel.com> - */ - -#include "cogl-config.h" - -#include <string.h> - -#include "cogl-context-private.h" -#include "cogl-pipeline-private.h" -#include "cogl-pipeline-layer-private.h" -#include "cogl-blend-string.h" -#include "cogl-snippet-private.h" -#include "cogl-list.h" -#include "driver/gl/cogl-util-gl-private.h" -#include "driver/gl/cogl-pipeline-opengl-private.h" - -#include "cogl-context-private.h" -#include "cogl-object-private.h" -#include "cogl-pipeline-cache.h" -#include "driver/gl/cogl-pipeline-fragend-glsl-private.h" -#include "deprecated/cogl-shader-private.h" -#include "deprecated/cogl-program-private.h" - -#include <glib.h> - -/* - * GL/GLES compatibility defines for pipeline thingies: - */ - -/* This might not be defined on GLES */ -#ifndef GL_TEXTURE_3D -#define GL_TEXTURE_3D 0x806F -#endif - -const CoglPipelineFragend _cogl_pipeline_glsl_backend; - -typedef struct _UnitState -{ - unsigned int sampled:1; - unsigned int combine_constant_used:1; -} UnitState; - -typedef struct _LayerData -{ - CoglList link; - - /* Layer index for the for the previous layer. This isn't - necessarily the same as this layer's index - 1 because the - indices can have gaps. If this is the first layer then it will be - -1 */ - int previous_layer_index; - - CoglPipelineLayer *layer; -} LayerData; - -typedef struct -{ - int ref_count; - - GLuint gl_shader; - GString *header, *source; - UnitState *unit_state; - - /* List of layers that we haven't generated code for yet. These are - in reverse order. As soon as we're about to generate code for - layer we'll remove it from the list so we don't generate it - again */ - CoglList layers; - - CoglPipelineCacheEntry *cache_entry; -} CoglPipelineShaderState; - -static CoglUserDataKey shader_state_key; - -static void -ensure_layer_generated (CoglPipeline *pipeline, - int layer_num); - -static CoglPipelineShaderState * -shader_state_new (int n_layers, - CoglPipelineCacheEntry *cache_entry) -{ - CoglPipelineShaderState *shader_state; - - shader_state = g_new0 (CoglPipelineShaderState, 1); - shader_state->ref_count = 1; - shader_state->unit_state = g_new0 (UnitState, n_layers); - shader_state->cache_entry = cache_entry; - - return shader_state; -} - -static CoglPipelineShaderState * -get_shader_state (CoglPipeline *pipeline) -{ - return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key); -} - -static void -destroy_shader_state (void *user_data, - void *instance) -{ - CoglPipelineShaderState *shader_state = user_data; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (shader_state->cache_entry && - shader_state->cache_entry->pipeline != instance) - shader_state->cache_entry->usage_count--; - - if (--shader_state->ref_count == 0) - { - if (shader_state->gl_shader) - GE( ctx, glDeleteShader (shader_state->gl_shader) ); - - g_free (shader_state->unit_state); - - g_free (shader_state); - } -} - -static void -set_shader_state (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state) -{ - if (shader_state) - { - shader_state->ref_count++; - - /* If we're not setting the state on the template pipeline then - * mark it as a usage of the pipeline cache entry */ - if (shader_state->cache_entry && - shader_state->cache_entry->pipeline != pipeline) - shader_state->cache_entry->usage_count++; - } - - _cogl_object_set_user_data (COGL_OBJECT (pipeline), - &shader_state_key, - shader_state, - destroy_shader_state); -} - -static void -dirty_shader_state (CoglPipeline *pipeline) -{ - cogl_object_set_user_data (COGL_OBJECT (pipeline), - &shader_state_key, - NULL, - NULL); -} - -GLuint -_cogl_pipeline_fragend_glsl_get_shader (CoglPipeline *pipeline) -{ - CoglPipelineShaderState *shader_state = get_shader_state (pipeline); - - if (shader_state) - return shader_state->gl_shader; - else - return 0; -} - -static CoglPipelineSnippetList * -get_fragment_snippets (CoglPipeline *pipeline) -{ - pipeline = - _cogl_pipeline_get_authority (pipeline, - COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS); - - return &pipeline->big_state->fragment_snippets; -} - -static CoglPipelineSnippetList * -get_layer_fragment_snippets (CoglPipelineLayer *layer) -{ - unsigned long state = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS; - layer = _cogl_pipeline_layer_get_authority (layer, state); - - return &layer->big_state->fragment_snippets; -} - -static gboolean -has_replace_hook (CoglPipelineLayer *layer, - CoglSnippetHook hook) -{ - GList *l; - - for (l = get_layer_fragment_snippets (layer)->entries; l; l = l->next) - { - CoglSnippet *snippet = l->data; - - if (snippet->hook == hook && snippet->replace) - return TRUE; - } - - return FALSE; -} - -static gboolean -add_layer_declaration_cb (CoglPipelineLayer *layer, - void *user_data) -{ - CoglPipelineShaderState *shader_state = user_data; - - g_string_append_printf (shader_state->header, - "uniform sampler2D cogl_sampler%i;\n", - layer->index); - - return TRUE; -} - -static void -add_layer_declarations (CoglPipeline *pipeline, - CoglPipelineShaderState *shader_state) -{ - /* We always emit sampler uniforms in case there will be custom - * layer snippets that want to sample arbitrary layers. */ - - _cogl_pipeline_foreach_layer_internal (pipeline, - add_layer_declaration_cb, - shader_state); -} - -static void -add_global_declarations (CoglPipeline *pipeline, - CoglPipelineShaderState *shader_state) -{ - CoglSnippetHook hook = COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS; - CoglPipelineSnippetList *snippets = get_fragment_snippets (pipeline); - - /* Add the global data hooks. All of the code in these snippets is - * always added and only the declarations data is used */ - - _cogl_pipeline_snippet_generate_declarations (shader_state->header, - hook, - snippets); -} - -static void -_cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline, - int n_layers, - unsigned long pipelines_difference) -{ - CoglPipelineShaderState *shader_state; - CoglPipeline *authority; - CoglPipelineCacheEntry *cache_entry = NULL; - CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline); - int i; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* Now lookup our glsl backend private state */ - shader_state = get_shader_state (pipeline); - - if (shader_state == NULL) - { - /* If we don't have an associated glsl shader yet then find the - * glsl-authority (the oldest ancestor whose state will result in - * the same shader being generated as for this pipeline). - * - * We always make sure to associate new shader with the - * glsl-authority to maximize the chance that other pipelines can - * share it. - */ - authority = _cogl_pipeline_find_equivalent_parent - (pipeline, - _cogl_pipeline_get_state_for_fragment_codegen (ctx) & - ~COGL_PIPELINE_STATE_LAYERS, - _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx)); - - shader_state = get_shader_state (authority); - - /* If we don't have an existing program associated with the - * glsl-authority then start generating code for a new shader... - */ - if (shader_state == NULL) - { - /* Check if there is already a similar cached pipeline whose - shader state we can share */ - if (G_LIKELY (!(COGL_DEBUG_ENABLED - (COGL_DEBUG_DISABLE_PROGRAM_CACHES)))) - { - cache_entry = - _cogl_pipeline_cache_get_fragment_template (ctx->pipeline_cache, - authority); - - shader_state = get_shader_state (cache_entry->pipeline); - } - - if (shader_state) - shader_state->ref_count++; - else - shader_state = shader_state_new (n_layers, cache_entry); - - set_shader_state (authority, shader_state); - - shader_state->ref_count--; - - if (cache_entry) - set_shader_state (cache_entry->pipeline, shader_state); - } - - /* If the pipeline isn't actually its own glsl-authority - * then take a reference to the program state associated - * with the glsl-authority... */ - if (authority != pipeline) - set_shader_state (pipeline, shader_state); - } - - if (user_program) - { - /* If the user program contains a fragment shader then we don't need - to generate one */ - if (_cogl_program_has_fragment_shader (user_program)) - { - if (shader_state->gl_shader) - { - GE( ctx, glDeleteShader (shader_state->gl_shader) ); - shader_state->gl_shader = 0; - } - return; - } - } - - if (shader_state->gl_shader) - return; - - /* If we make it here then we have a glsl_shader_state struct - without a gl_shader either because this is the first time we've - encountered it or because the user program has changed */ - - /* We reuse two grow-only GStrings for code-gen. One string - contains the uniform and attribute declarations while the - other contains the main function. We need two strings - because we need to dynamically declare attributes as the - add_layer callback is invoked */ - g_string_set_size (ctx->codegen_header_buffer, 0); - g_string_set_size (ctx->codegen_source_buffer, 0); - shader_state->header = ctx->codegen_header_buffer; - shader_state->source = ctx->codegen_source_buffer; - _cogl_list_init (&shader_state->layers); - - add_layer_declarations (pipeline, shader_state); - add_global_declarations (pipeline, shader_state); - - g_string_append (shader_state->source, - "void\n" - "cogl_generated_source ()\n" - "{\n"); - - for (i = 0; i < n_layers; i++) - { - shader_state->unit_state[i].sampled = FALSE; - shader_state->unit_state[i].combine_constant_used = FALSE; - } -} - -static void -add_constant_lookup (CoglPipelineShaderState *shader_state, - CoglPipeline *pipeline, - CoglPipelineLayer *layer, - const char *swizzle) -{ - g_string_append_printf (shader_state->header, - "_cogl_layer_constant_%i.%s", - layer->index, swizzle); -} - -static void -ensure_texture_lookup_generated (CoglPipelineShaderState *shader_state, - CoglPipeline *pipeline, - CoglPipelineLayer *layer) -{ - int unit_index = _cogl_pipeline_layer_get_unit_index (layer); - CoglPipelineSnippetData snippet_data; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (shader_state->unit_state[unit_index].sampled) - return; - - shader_state->unit_state[unit_index].sampled = TRUE; - - g_string_append_printf (shader_state->header, - "vec4 cogl_texel%i;\n", - layer->index); - - g_string_append_printf (shader_state->source, - " cogl_texel%i = cogl_texture_lookup%i (" - "cogl_sampler%i, ", - layer->index, - layer->index, - layer->index); - - if (cogl_pipeline_get_layer_point_sprite_coords_enabled (pipeline, - layer->index)) - g_string_append_printf (shader_state->source, - "vec4 (cogl_point_coord, 0.0, 1.0)"); - else - g_string_append_printf (shader_state->source, - "cogl_tex_coord%i_in", - layer->index); - - g_string_append (shader_state->source, ");\n"); - - /* There's no need to generate the real texture lookup if it's going - to be replaced */ - if (!has_replace_hook (layer, COGL_SNIPPET_HOOK_TEXTURE_LOOKUP)) - { - g_string_append_printf (shader_state->header, - "vec4\n" - "cogl_real_texture_lookup%i (sampler2D tex,\n" - " vec4 coords)\n" - "{\n" - " return ", - layer->index); - - if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING))) - g_string_append (shader_state->header, - "vec4 (1.0, 1.0, 1.0, 1.0);\n"); - else - g_string_append (shader_state->header, - "texture2D (tex, coords.st);\n"); - - g_string_append (shader_state->header, "}\n"); - } - - /* Wrap the texture lookup in any snippets that have been hooked */ - memset (&snippet_data, 0, sizeof (snippet_data)); - snippet_data.snippets = get_layer_fragment_snippets (layer); - snippet_data.hook = COGL_SNIPPET_HOOK_TEXTURE_LOOKUP; - snippet_data.chain_function = g_strdup_printf ("cogl_real_texture_lookup%i", - layer->index); - snippet_data.final_name = g_strdup_printf ("cogl_texture_lookup%i", - layer->index); - snippet_data.function_prefix = g_strdup_printf ("cogl_texture_lookup_hook%i", - layer->index); - snippet_data.return_type = "vec4"; - snippet_data.return_variable = "cogl_texel"; - snippet_data.arguments = "cogl_sampler, cogl_tex_coord"; - snippet_data.argument_declarations = - g_strdup ("sampler2D cogl_sampler, vec4 cogl_tex_coord"); - snippet_data.source_buf = shader_state->header; - - _cogl_pipeline_snippet_generate_code (&snippet_data); - - g_free ((char *) snippet_data.chain_function); - g_free ((char *) snippet_data.final_name); - g_free ((char *) snippet_data.function_prefix); - g_free ((char *) snippet_data.argument_declarations); -} - -static void -add_arg (CoglPipelineShaderState *shader_state, - CoglPipeline *pipeline, - CoglPipelineLayer *layer, - int previous_layer_index, - CoglPipelineCombineSource src, - CoglPipelineCombineOp operand, - const char *swizzle) -{ - GString *shader_source = shader_state->header; - char alpha_swizzle[5] = "aaaa"; - - g_string_append_c (shader_source, '('); - - if (operand == COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR || - operand == COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA) - g_string_append_printf (shader_source, - "vec4(1.0, 1.0, 1.0, 1.0).%s - ", - swizzle); - - /* If the operand is reading from the alpha then replace the swizzle - with the same number of copies of the alpha */ - if (operand == COGL_PIPELINE_COMBINE_OP_SRC_ALPHA || - operand == COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA) - { - alpha_swizzle[strlen (swizzle)] = '\0'; - swizzle = alpha_swizzle; - } - - switch (src) - { - case COGL_PIPELINE_COMBINE_SOURCE_TEXTURE: - g_string_append_printf (shader_source, - "cogl_texel%i.%s", - layer->index, - swizzle); - break; - - case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT: - add_constant_lookup (shader_state, - pipeline, - layer, - swizzle); - break; - - case COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS: - if (previous_layer_index >= 0) - { - g_string_append_printf (shader_source, - "cogl_layer%i.%s", - previous_layer_index, - swizzle); - break; - } - /* flow through */ - case COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR: - g_string_append_printf (shader_source, "cogl_color_in.%s", swizzle); - break; - - default: - { - int layer_num = src - COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0; - CoglPipelineGetLayerFlags flags = COGL_PIPELINE_GET_LAYER_NO_CREATE; - CoglPipelineLayer *other_layer = - _cogl_pipeline_get_layer_with_flags (pipeline, layer_num, flags); - - if (other_layer == NULL) - { - static gboolean warning_seen = FALSE; - if (!warning_seen) - { - g_warning ("The application is trying to use a texture " - "combine with a layer number that does not exist"); - warning_seen = TRUE; - } - g_string_append_printf (shader_source, - "vec4 (1.0, 1.0, 1.0, 1.0).%s", - swizzle); - } - else - g_string_append_printf (shader_source, - "cogl_texel%i.%s", - other_layer->index, - swizzle); - } - break; - } - - g_string_append_c (shader_source, ')'); -} - -static void -ensure_arg_generated (CoglPipeline *pipeline, - CoglPipelineLayer *layer, - int previous_layer_index, - CoglPipelineCombineSource src) -{ - CoglPipelineShaderState *shader_state = get_shader_state (pipeline); - - switch (src) - { - case COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR: - /* This doesn't involve any other layers */ - break; - - case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT: - { - int unit_index = _cogl_pipeline_layer_get_unit_index (layer); - /* Create a sampler uniform for this layer if we haven't already */ - if (!shader_state->unit_state[unit_index].combine_constant_used) - { - g_string_append_printf (shader_state->header, - "uniform vec4 _cogl_layer_constant_%i;\n", - layer->index); - shader_state->unit_state[unit_index].combine_constant_used = TRUE; - } - } - break; - - case COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS: - if (previous_layer_index >= 0) - ensure_layer_generated (pipeline, previous_layer_index); - break; - - case COGL_PIPELINE_COMBINE_SOURCE_TEXTURE: - ensure_texture_lookup_generated (shader_state, - pipeline, - layer); - break; - - default: - if (src >= COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0) - { - int layer_num = src - COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0; - CoglPipelineGetLayerFlags flags = COGL_PIPELINE_GET_LAYER_NO_CREATE; - CoglPipelineLayer *other_layer = - _cogl_pipeline_get_layer_with_flags (pipeline, layer_num, flags); - - if (other_layer) - ensure_texture_lookup_generated (shader_state, - pipeline, - other_layer); - } - break; - } -} - -static void -ensure_args_for_func (CoglPipeline *pipeline, - CoglPipelineLayer *layer, - int previous_layer_index, - CoglPipelineCombineFunc function, - CoglPipelineCombineSource *src) -{ - int n_args = _cogl_get_n_args_for_combine_func (function); - int i; - - for (i = 0; i < n_args; i++) - ensure_arg_generated (pipeline, layer, previous_layer_index, src[i]); -} - -static void -append_masked_combine (CoglPipeline *pipeline, - CoglPipelineLayer *layer, - int previous_layer_index, - const char *swizzle, - CoglPipelineCombineFunc function, - CoglPipelineCombineSource *src, - CoglPipelineCombineOp *op) -{ - CoglPipelineShaderState *shader_state = get_shader_state (pipeline); - GString *shader_source = shader_state->header; - - g_string_append_printf (shader_state->header, - " cogl_layer.%s = ", - swizzle); - - switch (function) - { - case COGL_PIPELINE_COMBINE_FUNC_REPLACE: - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[0], op[0], swizzle); - break; - - case COGL_PIPELINE_COMBINE_FUNC_MODULATE: - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[0], op[0], swizzle); - g_string_append (shader_source, " * "); - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[1], op[1], swizzle); - break; - - case COGL_PIPELINE_COMBINE_FUNC_ADD: - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[0], op[0], swizzle); - g_string_append (shader_source, " + "); - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[1], op[1], swizzle); - break; - - case COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED: - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[0], op[0], swizzle); - g_string_append (shader_source, " + "); - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[1], op[1], swizzle); - g_string_append_printf (shader_source, - " - vec4(0.5, 0.5, 0.5, 0.5).%s", - swizzle); - break; - - case COGL_PIPELINE_COMBINE_FUNC_SUBTRACT: - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[0], op[0], swizzle); - g_string_append (shader_source, " - "); - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[1], op[1], swizzle); - break; - - case COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE: - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[0], op[0], swizzle); - g_string_append (shader_source, " * "); - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[2], op[2], swizzle); - g_string_append (shader_source, " + "); - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[1], op[1], swizzle); - g_string_append_printf (shader_source, - " * (vec4(1.0, 1.0, 1.0, 1.0).%s - ", - swizzle); - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[2], op[2], swizzle); - g_string_append_c (shader_source, ')'); - break; - - case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB: - case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA: - g_string_append (shader_source, "vec4(4.0 * (("); - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[0], op[0], "r"); - g_string_append (shader_source, " - 0.5) * ("); - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[1], op[1], "r"); - g_string_append (shader_source, " - 0.5) + ("); - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[0], op[0], "g"); - g_string_append (shader_source, " - 0.5) * ("); - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[1], op[1], "g"); - g_string_append (shader_source, " - 0.5) + ("); - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[0], op[0], "b"); - g_string_append (shader_source, " - 0.5) * ("); - add_arg (shader_state, pipeline, layer, previous_layer_index, - src[1], op[1], "b"); - g_string_append_printf (shader_source, " - 0.5))).%s", swizzle); - break; - } - - g_string_append_printf (shader_source, ";\n"); -} - -static void -ensure_layer_generated (CoglPipeline *pipeline, - int layer_index) -{ - CoglPipelineShaderState *shader_state = get_shader_state (pipeline); - CoglPipelineLayer *combine_authority; - CoglPipelineLayerBigState *big_state; - CoglPipelineLayer *layer; - CoglPipelineSnippetData snippet_data; - LayerData *layer_data; - - /* Find the layer that corresponds to this layer_num */ - _cogl_list_for_each (layer_data, &shader_state->layers, link) - { - layer = layer_data->layer; - - if (layer->index == layer_index) - goto found; - } - - /* If we didn't find it then we can assume the layer has already - been generated */ - return; - - found: - - /* Remove the layer from the list so we don't generate it again */ - _cogl_list_remove (&layer_data->link); - - combine_authority = - _cogl_pipeline_layer_get_authority (layer, - COGL_PIPELINE_LAYER_STATE_COMBINE); - big_state = combine_authority->big_state; - - /* Make a global variable for the result of the layer code */ - g_string_append_printf (shader_state->header, - "vec4 cogl_layer%i;\n", - layer_index); - - /* Skip the layer generation if there is a snippet that replaces the - default layer code. This is important because generating this - code may cause the code for other layers to be generated and - stored in the global variable. If this code isn't actually used - then the global variables would be uninitialised and they may be - used from other layers */ - if (!has_replace_hook (layer, COGL_SNIPPET_HOOK_LAYER_FRAGMENT)) - { - ensure_args_for_func (pipeline, - layer, - layer_data->previous_layer_index, - big_state->texture_combine_rgb_func, - big_state->texture_combine_rgb_src); - ensure_args_for_func (pipeline, - layer, - layer_data->previous_layer_index, - big_state->texture_combine_alpha_func, - big_state->texture_combine_alpha_src); - - g_string_append_printf (shader_state->header, - "vec4\n" - "cogl_real_generate_layer%i ()\n" - "{\n" - " vec4 cogl_layer;\n", - layer_index); - - if (!_cogl_pipeline_layer_needs_combine_separate (combine_authority) || - /* GL_DOT3_RGBA Is a bit weird as a GL_COMBINE_RGB function - * since if you use it, it overrides your ALPHA function... - */ - big_state->texture_combine_rgb_func == - COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA) - append_masked_combine (pipeline, - layer, - layer_data->previous_layer_index, - "rgba", - big_state->texture_combine_rgb_func, - big_state->texture_combine_rgb_src, - big_state->texture_combine_rgb_op); - else - { - append_masked_combine (pipeline, - layer, - layer_data->previous_layer_index, - "rgb", - big_state->texture_combine_rgb_func, - big_state->texture_combine_rgb_src, - big_state->texture_combine_rgb_op); - append_masked_combine (pipeline, - layer, - layer_data->previous_layer_index, - "a", - big_state->texture_combine_alpha_func, - big_state->texture_combine_alpha_src, - big_state->texture_combine_alpha_op); - } - - g_string_append (shader_state->header, - " return cogl_layer;\n" - "}\n"); - } - - /* Wrap the layer code in any snippets that have been hooked */ - memset (&snippet_data, 0, sizeof (snippet_data)); - snippet_data.snippets = get_layer_fragment_snippets (layer); - snippet_data.hook = COGL_SNIPPET_HOOK_LAYER_FRAGMENT; - snippet_data.chain_function = g_strdup_printf ("cogl_real_generate_layer%i", - layer_index); - snippet_data.final_name = g_strdup_printf ("cogl_generate_layer%i", - layer_index); - snippet_data.function_prefix = g_strdup_printf ("cogl_generate_layer%i", - layer_index); - snippet_data.return_type = "vec4"; - snippet_data.return_variable = "cogl_layer"; - snippet_data.source_buf = shader_state->header; - - _cogl_pipeline_snippet_generate_code (&snippet_data); - - g_free ((char *) snippet_data.chain_function); - g_free ((char *) snippet_data.final_name); - g_free ((char *) snippet_data.function_prefix); - - g_string_append_printf (shader_state->source, - " cogl_layer%i = cogl_generate_layer%i ();\n", - layer_index, - layer_index); - - g_free (layer_data); -} - -static gboolean -_cogl_pipeline_fragend_glsl_add_layer (CoglPipeline *pipeline, - CoglPipelineLayer *layer, - unsigned long layers_difference) -{ - CoglPipelineShaderState *shader_state = get_shader_state (pipeline); - LayerData *layer_data; - - if (!shader_state->source) - return TRUE; - - /* Store the layers in reverse order */ - layer_data = g_new0 (LayerData, 1); - layer_data->layer = layer; - - if (_cogl_list_empty (&shader_state->layers)) - { - layer_data->previous_layer_index = -1; - } - else - { - LayerData *first = - _cogl_container_of (shader_state->layers.next, LayerData, link); - layer_data->previous_layer_index = first->layer->index; - } - - _cogl_list_insert (&shader_state->layers, &layer_data->link); - - return TRUE; -} - -/* GLES2 and GL3 don't have alpha testing so we need to implement it - in the shader */ - -#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) - -static void -add_alpha_test_snippet (CoglPipeline *pipeline, - CoglPipelineShaderState *shader_state) -{ - CoglPipelineAlphaFunc alpha_func; - - alpha_func = cogl_pipeline_get_alpha_test_function (pipeline); - - if (alpha_func == COGL_PIPELINE_ALPHA_FUNC_ALWAYS) - /* Do nothing */ - return; - - if (alpha_func == COGL_PIPELINE_ALPHA_FUNC_NEVER) - { - /* Always discard the fragment */ - g_string_append (shader_state->source, - " discard;\n"); - return; - } - - /* For all of the other alpha functions we need a uniform for the - reference */ - - g_string_append (shader_state->header, - "uniform float _cogl_alpha_test_ref;\n"); - - g_string_append (shader_state->source, - " if (cogl_color_out.a "); - - switch (alpha_func) - { - case COGL_PIPELINE_ALPHA_FUNC_LESS: - g_string_append (shader_state->source, ">="); - break; - case COGL_PIPELINE_ALPHA_FUNC_EQUAL: - g_string_append (shader_state->source, "!="); - break; - case COGL_PIPELINE_ALPHA_FUNC_LEQUAL: - g_string_append (shader_state->source, ">"); - break; - case COGL_PIPELINE_ALPHA_FUNC_GREATER: - g_string_append (shader_state->source, "<="); - break; - case COGL_PIPELINE_ALPHA_FUNC_NOTEQUAL: - g_string_append (shader_state->source, "=="); - break; - case COGL_PIPELINE_ALPHA_FUNC_GEQUAL: - g_string_append (shader_state->source, "< "); - break; - - case COGL_PIPELINE_ALPHA_FUNC_ALWAYS: - case COGL_PIPELINE_ALPHA_FUNC_NEVER: - g_assert_not_reached (); - break; - } - - g_string_append (shader_state->source, - " _cogl_alpha_test_ref)\n discard;\n"); -} - -#endif /* HAVE_COGL_GLES2 */ - -static gboolean -_cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline, - unsigned long pipelines_difference) -{ - CoglPipelineShaderState *shader_state = get_shader_state (pipeline); - - _COGL_GET_CONTEXT (ctx, FALSE); - - if (shader_state->source) - { - const char *source_strings[2]; - GLint lengths[2]; - GLint compile_status; - GLuint shader; - CoglPipelineSnippetData snippet_data; - - COGL_STATIC_COUNTER (fragend_glsl_compile_counter, - "glsl fragment compile counter", - "Increments each time a new GLSL " - "fragment shader is compiled", - 0 /* no application private data */); - COGL_COUNTER_INC (_cogl_uprof_context, fragend_glsl_compile_counter); - - /* We only need to generate code to calculate the fragment value - for the last layer. If the value of this layer depends on any - previous layers then it will recursively generate the code - for those layers */ - if (!_cogl_list_empty (&shader_state->layers)) - { - CoglPipelineLayer *last_layer; - LayerData *layer_data, *tmp; - - layer_data = _cogl_container_of (shader_state->layers.next, - LayerData, - link); - last_layer = layer_data->layer; - - ensure_layer_generated (pipeline, last_layer->index); - g_string_append_printf (shader_state->source, - " cogl_color_out = cogl_layer%i;\n", - last_layer->index); - - _cogl_list_for_each_safe (layer_data, - tmp, - &shader_state->layers, - link) - g_free (layer_data); - } - else - g_string_append (shader_state->source, - " cogl_color_out = cogl_color_in;\n"); - - add_alpha_test_snippet (pipeline, shader_state); - - /* Close the function surrounding the generated fragment processing */ - g_string_append (shader_state->source, "}\n"); - - /* Add all of the hooks for fragment processing */ - memset (&snippet_data, 0, sizeof (snippet_data)); - snippet_data.snippets = get_fragment_snippets (pipeline); - snippet_data.hook = COGL_SNIPPET_HOOK_FRAGMENT; - snippet_data.chain_function = "cogl_generated_source"; - snippet_data.final_name = "main"; - snippet_data.function_prefix = "cogl_fragment_hook"; - snippet_data.source_buf = shader_state->source; - _cogl_pipeline_snippet_generate_code (&snippet_data); - - GE_RET( shader, ctx, glCreateShader (GL_FRAGMENT_SHADER) ); - - lengths[0] = shader_state->header->len; - source_strings[0] = shader_state->header->str; - lengths[1] = shader_state->source->len; - source_strings[1] = shader_state->source->str; - - _cogl_glsl_shader_set_source_with_boilerplate (ctx, - shader, GL_FRAGMENT_SHADER, - pipeline, - 2, /* count */ - source_strings, lengths); - - GE( ctx, glCompileShader (shader) ); - GE( ctx, glGetShaderiv (shader, GL_COMPILE_STATUS, &compile_status) ); - - if (!compile_status) - { - GLint len = 0; - char *shader_log; - - GE( ctx, glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &len) ); - shader_log = g_alloca (len); - GE( ctx, glGetShaderInfoLog (shader, len, &len, shader_log) ); - g_warning ("Shader compilation failed:\n%s", shader_log); - } - - shader_state->header = NULL; - shader_state->source = NULL; - shader_state->gl_shader = shader; - } - - return TRUE; -} - -static void -_cogl_pipeline_fragend_glsl_pre_change_notify (CoglPipeline *pipeline, - CoglPipelineState change, - const CoglColor *new_color) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx))) - dirty_shader_state (pipeline); -} - -/* NB: layers are considered immutable once they have any dependants - * so although multiple pipelines can end up depending on a single - * static layer, we can guarantee that if a layer is being *changed* - * then it can only have one pipeline depending on it. - * - * XXX: Don't forget this is *pre* change, we can't read the new value - * yet! - */ -static void -_cogl_pipeline_fragend_glsl_layer_pre_change_notify ( - CoglPipeline *owner, - CoglPipelineLayer *layer, - CoglPipelineLayerState change) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if ((change & _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx))) - { - dirty_shader_state (owner); - return; - } - - /* TODO: we could be saving snippets of texture combine code along - * with each layer and then when a layer changes we would just free - * the snippet. */ -} - -const CoglPipelineFragend _cogl_pipeline_glsl_fragend = -{ - _cogl_pipeline_fragend_glsl_start, - _cogl_pipeline_fragend_glsl_add_layer, - _cogl_pipeline_fragend_glsl_end, - _cogl_pipeline_fragend_glsl_pre_change_notify, - _cogl_pipeline_fragend_glsl_layer_pre_change_notify -}; diff --git a/cogl/cogl/driver/gl/cogl-pipeline-opengl-private.h b/cogl/cogl/driver/gl/cogl-pipeline-opengl-private.h deleted file mode 100644 index 3626fd16c..000000000 --- a/cogl/cogl/driver/gl/cogl-pipeline-opengl-private.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2010 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Robert Bragg <robert@linux.intel.com> - */ - -#ifndef __COGL_PIPELINE_OPENGL_PRIVATE_H -#define __COGL_PIPELINE_OPENGL_PRIVATE_H - -#include "cogl-pipeline-private.h" -#include "cogl-matrix-stack.h" - -/* - * cogl-pipeline.c owns the GPU's texture unit state so we have some - * private structures for describing the current state of a texture - * unit that we track in a per context array (ctx->texture_units) that - * grows according to the largest texture unit used so far... - * - * Roughly speaking the members in this structure are of two kinds: - * either they are a low level reflection of the state we send to - * OpenGL or they are for high level meta data associated with the - * texture unit when flushing CoglPipelineLayers that is typically - * used to optimize subsequent re-flushing of the same layer. - * - * The low level members are at the top, and the high level members - * start with the .layer member. - */ -typedef struct _CoglTextureUnit -{ - /* The base 0 texture unit index which can be used with - * glActiveTexture () */ - int index; - - /* The GL target currently glEnabled or 0 if nothing is - * enabled. This is only used by the fixed pipeline fragend */ - GLenum enabled_gl_target; - - /* The raw GL texture object name for which we called glBindTexture when - * we flushed the last layer. (NB: The CoglTexture associated - * with a layer may represent more than one GL texture) */ - GLuint gl_texture; - /* The target of the GL texture object. This is just used so that we - * can quickly determine the intended target to flush when - * dirty_gl_texture == TRUE */ - GLenum gl_target; - - /* We have many components in Cogl that need to temporarily bind arbitrary - * textures e.g. to query texture object parameters and since we don't - * want that to result in too much redundant reflushing of layer state - * when all that's needed is to re-bind the layer's gl_texture we use this - * to track when the unit->gl_texture state is out of sync with the GL - * texture object really bound too (GL_TEXTURE0+unit->index). - * - * XXX: as a further optimization cogl-pipeline.c uses a convention - * of always using texture unit 1 for these transient bindings so we - * can assume this is only ever TRUE for unit 1. - */ - gboolean dirty_gl_texture; - - /* A matrix stack giving us the means to associate a texture - * transform matrix with the texture unit. */ - CoglMatrixStack *matrix_stack; - - /* - * Higher level layer state associated with the unit... - */ - - /* The CoglPipelineLayer whose state was flushed to update this - * texture unit last. - * - * This will be set to NULL if the layer is modified or freed which - * means when we come to flush a layer; if this pointer is still - * valid and == to the layer being flushed we don't need to update - * any texture unit state. */ - CoglPipelineLayer *layer; - - /* To help minimize the state changes required we track the - * difference flags associated with the layer whose state was last - * flushed to update this texture unit. - * - * Note: we track this explicitly because .layer may get invalidated - * if that layer is modified or deleted. Even if the layer is - * invalidated though these flags can be used to optimize the state - * flush of the next layer - */ - unsigned long layer_changes_since_flush; - - /* Whenever a CoglTexture's internal GL texture storage changes - * cogl-pipeline.c is notified with a call to - * _cogl_pipeline_texture_storage_change_notify which inturn sets - * this to TRUE for each texture unit that it is currently bound - * too. When we later come to flush some pipeline state then we will - * always check this to potentially force an update of the texture - * state even if the pipeline hasn't changed. */ - gboolean texture_storage_changed; - -} CoglTextureUnit; - -CoglTextureUnit * -_cogl_get_texture_unit (int index_); - -void -_cogl_destroy_texture_units (CoglContext *ctx); - -void -_cogl_set_active_texture_unit (int unit_index); - -void -_cogl_bind_gl_texture_transient (GLenum gl_target, - GLuint gl_texture); - -void -_cogl_delete_gl_texture (GLuint gl_texture); - -void -_cogl_pipeline_flush_gl_state (CoglContext *context, - CoglPipeline *pipeline, - CoglFramebuffer *framebuffer, - gboolean skip_gl_state, - gboolean unknown_color_alpha); - -void -_cogl_glsl_shader_set_source_with_boilerplate (CoglContext *ctx, - GLuint shader_gl_handle, - GLenum shader_gl_type, - CoglPipeline *pipeline, - GLsizei count_in, - const char **strings_in, - const GLint *lengths_in); - -void -_cogl_sampler_gl_init (CoglContext *context, - CoglSamplerCacheEntry *entry); - -void -_cogl_sampler_gl_free (CoglContext *context, - CoglSamplerCacheEntry *entry); - -void -_cogl_gl_set_uniform (CoglContext *ctx, - GLint location, - const CoglBoxedValue *value); - -#endif /* __COGL_PIPELINE_OPENGL_PRIVATE_H */ - diff --git a/cogl/cogl/driver/gl/cogl-pipeline-opengl.c b/cogl/cogl/driver/gl/cogl-pipeline-opengl.c deleted file mode 100644 index 9d487714b..000000000 --- a/cogl/cogl/driver/gl/cogl-pipeline-opengl.c +++ /dev/null @@ -1,1285 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2008,2009,2010 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Robert Bragg <robert@linux.intel.com> - */ - -#include "cogl-config.h" - -#include "cogl-debug.h" -#include "cogl-pipeline-private.h" -#include "cogl-context-private.h" -#include "cogl-texture-private.h" -#include "cogl-framebuffer-private.h" -#include "cogl-offscreen.h" -#include "driver/gl/cogl-util-gl-private.h" -#include "driver/gl/cogl-pipeline-opengl-private.h" -#include "driver/gl/cogl-texture-gl-private.h" - -#include "driver/gl/cogl-pipeline-progend-glsl-private.h" - -#include <test-fixtures/test-unit.h> - -#include <glib.h> -#include <string.h> - -/* - * GL/GLES compatibility defines for pipeline thingies: - */ - -/* These aren't defined in the GLES headers */ -#ifndef GL_POINT_SPRITE -#define GL_POINT_SPRITE 0x8861 -#endif -#ifndef GL_COORD_REPLACE -#define GL_COORD_REPLACE 0x8862 -#endif -#ifndef GL_CLAMP_TO_BORDER -#define GL_CLAMP_TO_BORDER 0x812d -#endif - -static void -texture_unit_init (CoglContext *ctx, - CoglTextureUnit *unit, - int index_) -{ - unit->index = index_; - unit->enabled_gl_target = 0; - unit->gl_texture = 0; - unit->gl_target = 0; - unit->dirty_gl_texture = FALSE; - unit->matrix_stack = cogl_matrix_stack_new (ctx); - - unit->layer = NULL; - unit->layer_changes_since_flush = 0; - unit->texture_storage_changed = FALSE; -} - -static void -texture_unit_free (CoglTextureUnit *unit) -{ - if (unit->layer) - cogl_object_unref (unit->layer); - cogl_object_unref (unit->matrix_stack); -} - -CoglTextureUnit * -_cogl_get_texture_unit (int index_) -{ - _COGL_GET_CONTEXT (ctx, NULL); - CoglGLContext *glctx = _cogl_driver_gl_context(ctx); - - if (glctx->texture_units->len < (index_ + 1)) - { - int i; - int prev_len = glctx->texture_units->len; - glctx->texture_units = g_array_set_size (glctx->texture_units, - index_ + 1); - for (i = prev_len; i <= index_; i++) - { - CoglTextureUnit *unit = - &g_array_index (glctx->texture_units, CoglTextureUnit, i); - - texture_unit_init (ctx, unit, i); - } - } - - return &g_array_index (glctx->texture_units, CoglTextureUnit, index_); -} - -void -_cogl_destroy_texture_units (CoglContext *ctx) -{ - int i; - CoglGLContext *glctx = _cogl_driver_gl_context(ctx); - - for (i = 0; i < glctx->texture_units->len; i++) - { - CoglTextureUnit *unit = - &g_array_index (glctx->texture_units, CoglTextureUnit, i); - texture_unit_free (unit); - } - g_array_free (glctx->texture_units, TRUE); -} - -void -_cogl_set_active_texture_unit (int unit_index) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - CoglGLContext *glctx = _cogl_driver_gl_context(ctx); - - if (glctx->active_texture_unit != unit_index) - { - GE (ctx, glActiveTexture (GL_TEXTURE0 + unit_index)); - glctx->active_texture_unit = unit_index; - } -} - -/* Note: _cogl_bind_gl_texture_transient conceptually has slightly - * different semantics to OpenGL's glBindTexture because Cogl never - * cares about tracking multiple textures bound to different targets - * on the same texture unit. - * - * glBindTexture lets you bind multiple textures to a single texture - * unit if they are bound to different targets. So it does something - * like: - * unit->current_texture[target] = texture; - * - * Cogl only lets you associate one texture with the currently active - * texture unit, so the target is basically a redundant parameter - * that's implicitly set on that texture. - * - * Technically this is just a thin wrapper around glBindTexture so - * actually it does have the GL semantics but it seems worth - * mentioning the conceptual difference in case anyone wonders why we - * don't associate the gl_texture with a gl_target in the - * CoglTextureUnit. - */ -void -_cogl_bind_gl_texture_transient (GLenum gl_target, - GLuint gl_texture) -{ - CoglTextureUnit *unit; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* We choose to always make texture unit 1 active for transient - * binds so that in the common case where multitexturing isn't used - * we can simply ignore the state of this texture unit. Notably we - * didn't use a large texture unit (.e.g. (GL_MAX_TEXTURE_UNITS - 1) - * in case the driver doesn't have a sparse data structure for - * texture units. - */ - _cogl_set_active_texture_unit (1); - unit = _cogl_get_texture_unit (1); - - if (unit->gl_texture == gl_texture && !unit->dirty_gl_texture) - return; - - GE (ctx, glBindTexture (gl_target, gl_texture)); - - unit->dirty_gl_texture = TRUE; -} - -void -_cogl_delete_gl_texture (GLuint gl_texture) -{ - int i; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - CoglGLContext *glctx = _cogl_driver_gl_context(ctx); - - for (i = 0; i < glctx->texture_units->len; i++) - { - CoglTextureUnit *unit = - &g_array_index (glctx->texture_units, CoglTextureUnit, i); - - if (unit->gl_texture == gl_texture) - { - unit->gl_texture = 0; - unit->gl_target = 0; - unit->dirty_gl_texture = FALSE; - } - } - - GE (ctx, glDeleteTextures (1, &gl_texture)); -} - -/* Whenever the underlying GL texture storage of a CoglTexture is - * changed (e.g. due to migration out of a texture atlas) then we are - * notified. This lets us ensure that we reflush that texture's state - * if it is reused again with the same texture unit. - */ -void -_cogl_pipeline_texture_storage_change_notify (CoglTexture *texture) -{ - int i; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - CoglGLContext *glctx = _cogl_driver_gl_context(ctx); - - for (i = 0; i < glctx->texture_units->len; i++) - { - CoglTextureUnit *unit = - &g_array_index (glctx->texture_units, CoglTextureUnit, i); - - if (unit->layer && - _cogl_pipeline_layer_get_texture (unit->layer) == texture) - unit->texture_storage_changed = TRUE; - - /* NB: the texture may be bound to multiple texture units so - * we continue to check the rest */ - } -} - -#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) - -static gboolean -blend_factor_uses_constant (GLenum blend_factor) -{ - return (blend_factor == GL_CONSTANT_COLOR || - blend_factor == GL_ONE_MINUS_CONSTANT_COLOR || - blend_factor == GL_CONSTANT_ALPHA || - blend_factor == GL_ONE_MINUS_CONSTANT_ALPHA); -} - -#endif - -static void -flush_depth_state (CoglContext *ctx, - CoglDepthState *depth_state) -{ - gboolean depth_writing_enabled = depth_state->write_enabled; - - if (ctx->current_draw_buffer) - { - depth_writing_enabled &= - cogl_framebuffer_get_depth_write_enabled (ctx->current_draw_buffer); - } - - if (ctx->depth_test_enabled_cache != depth_state->test_enabled) - { - if (depth_state->test_enabled == TRUE) - { - GE (ctx, glEnable (GL_DEPTH_TEST)); - if (ctx->current_draw_buffer) - cogl_framebuffer_set_depth_buffer_clear_needed (ctx->current_draw_buffer); - } - else - GE (ctx, glDisable (GL_DEPTH_TEST)); - ctx->depth_test_enabled_cache = depth_state->test_enabled; - } - - if (ctx->depth_test_function_cache != depth_state->test_function && - depth_state->test_enabled == TRUE) - { - GE (ctx, glDepthFunc (depth_state->test_function)); - ctx->depth_test_function_cache = depth_state->test_function; - } - - if (ctx->depth_writing_enabled_cache != depth_writing_enabled) - { - GE (ctx, glDepthMask (depth_writing_enabled ? - GL_TRUE : GL_FALSE)); - ctx->depth_writing_enabled_cache = depth_writing_enabled; - } - - if ((ctx->depth_range_near_cache != depth_state->range_near || - ctx->depth_range_far_cache != depth_state->range_far)) - { - if (ctx->driver == COGL_DRIVER_GLES2) - GE (ctx, glDepthRangef (depth_state->range_near, - depth_state->range_far)); - else - GE (ctx, glDepthRange (depth_state->range_near, - depth_state->range_far)); - - ctx->depth_range_near_cache = depth_state->range_near; - ctx->depth_range_far_cache = depth_state->range_far; - } -} - -UNIT_TEST (check_gl_blend_enable, - 0 /* no requirements */, - 0 /* no failure cases */) -{ - CoglPipeline *pipeline = cogl_pipeline_new (test_ctx); - - /* By default blending should be disabled */ - g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 0); - - cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 1, 1); - _cogl_framebuffer_flush_journal (test_fb); - - /* After drawing an opaque rectangle blending should still be - * disabled */ - g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 0); - - cogl_pipeline_set_color4f (pipeline, 0, 0, 0, 0); - cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 1, 1); - _cogl_framebuffer_flush_journal (test_fb); - - /* After drawing a transparent rectangle blending should be enabled */ - g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 1); - - cogl_pipeline_set_blend (pipeline, "RGBA=ADD(SRC_COLOR, 0)", NULL); - cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 1, 1); - _cogl_framebuffer_flush_journal (test_fb); - - /* After setting a blend string that effectively disables blending - * then blending should be disabled */ - g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 0); -} - -static void -_cogl_pipeline_flush_color_blend_alpha_depth_state ( - CoglPipeline *pipeline, - unsigned long pipelines_difference, - gboolean with_color_attrib) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (pipelines_difference & COGL_PIPELINE_STATE_BLEND) - { - CoglPipeline *authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND); - CoglPipelineBlendState *blend_state = - &authority->big_state->blend_state; - -#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL) - if (blend_factor_uses_constant (blend_state->blend_src_factor_rgb) || - blend_factor_uses_constant (blend_state - ->blend_src_factor_alpha) || - blend_factor_uses_constant (blend_state->blend_dst_factor_rgb) || - blend_factor_uses_constant (blend_state->blend_dst_factor_alpha)) - { - float red = - cogl_color_get_red_float (&blend_state->blend_constant); - float green = - cogl_color_get_green_float (&blend_state->blend_constant); - float blue = - cogl_color_get_blue_float (&blend_state->blend_constant); - float alpha = - cogl_color_get_alpha_float (&blend_state->blend_constant); - - - GE (ctx, glBlendColor (red, green, blue, alpha)); - } - - GE (ctx, glBlendEquationSeparate (blend_state->blend_equation_rgb, - blend_state->blend_equation_alpha)); - - GE (ctx, glBlendFuncSeparate (blend_state->blend_src_factor_rgb, - blend_state->blend_dst_factor_rgb, - blend_state->blend_src_factor_alpha, - blend_state->blend_dst_factor_alpha)); - } -#endif - - if (pipelines_difference & COGL_PIPELINE_STATE_DEPTH) - { - CoglPipeline *authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_DEPTH); - CoglDepthState *depth_state = &authority->big_state->depth_state; - - flush_depth_state (ctx, depth_state); - } - - if (pipelines_difference & COGL_PIPELINE_STATE_CULL_FACE) - { - CoglPipeline *authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_CULL_FACE); - CoglPipelineCullFaceState *cull_face_state - = &authority->big_state->cull_face_state; - - if (cull_face_state->mode == COGL_PIPELINE_CULL_FACE_MODE_NONE) - GE( ctx, glDisable (GL_CULL_FACE) ); - else - { - gboolean invert_winding; - - GE( ctx, glEnable (GL_CULL_FACE) ); - - switch (cull_face_state->mode) - { - case COGL_PIPELINE_CULL_FACE_MODE_NONE: - g_assert_not_reached (); - - case COGL_PIPELINE_CULL_FACE_MODE_FRONT: - GE( ctx, glCullFace (GL_FRONT) ); - break; - - case COGL_PIPELINE_CULL_FACE_MODE_BACK: - GE( ctx, glCullFace (GL_BACK) ); - break; - - case COGL_PIPELINE_CULL_FACE_MODE_BOTH: - GE( ctx, glCullFace (GL_FRONT_AND_BACK) ); - break; - } - - invert_winding = - cogl_framebuffer_is_y_flipped (ctx->current_draw_buffer); - - switch (cull_face_state->front_winding) - { - case COGL_WINDING_CLOCKWISE: - GE( ctx, glFrontFace (invert_winding ? GL_CCW : GL_CW) ); - break; - - case COGL_WINDING_COUNTER_CLOCKWISE: - GE( ctx, glFrontFace (invert_winding ? GL_CW : GL_CCW) ); - break; - } - } - } - - if (pipeline->real_blend_enable != ctx->gl_blend_enable_cache) - { - if (pipeline->real_blend_enable) - GE (ctx, glEnable (GL_BLEND)); - else - GE (ctx, glDisable (GL_BLEND)); - /* XXX: we shouldn't update any other blend state if blending - * is disabled! */ - ctx->gl_blend_enable_cache = pipeline->real_blend_enable; - } -} - -static int -get_max_activateable_texture_units (void) -{ - _COGL_GET_CONTEXT (ctx, 0); - - if (G_UNLIKELY (ctx->max_activateable_texture_units == -1)) - { - GLint values[3]; - int n_values = 0; - int i; - -#ifdef HAVE_COGL_GL - if (ctx->driver != COGL_DRIVER_GLES2) - { - /* GL_MAX_TEXTURE_COORDS defines the number of texture coordinates - * that can be uploaded (but doesn't necessarily relate to how many - * texture images can be sampled) */ - GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_COORDS, values + n_values++)); - - GE (ctx, glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, - values + n_values++)); - } -#endif /* HAVE_COGL_GL */ - -#ifdef HAVE_COGL_GLES2 - if (ctx->driver == COGL_DRIVER_GLES2) - { - GE (ctx, glGetIntegerv (GL_MAX_VERTEX_ATTRIBS, values + n_values)); - /* Two of the vertex attribs need to be used for the position - and color */ - values[n_values++] -= 2; - - GE (ctx, glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, - values + n_values++)); - } -#endif - -#ifdef HAVE_COGL_GL - if (ctx->driver == COGL_DRIVER_GL) - { - /* GL_MAX_TEXTURE_UNITS defines the number of units that are - usable from the fixed function pipeline, therefore it isn't - available in GLES2. These are also tied to the number of - texture coordinates that can be uploaded so it should be less - than that available from the shader extensions */ - GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_UNITS, - values + n_values++)); - - } -#endif - - g_assert (n_values <= G_N_ELEMENTS (values) && - n_values > 0); - - /* Use the maximum value */ - ctx->max_activateable_texture_units = values[0]; - for (i = 1; i < n_values; i++) - ctx->max_activateable_texture_units = - MAX (values[i], ctx->max_activateable_texture_units); - } - - return ctx->max_activateable_texture_units; -} - -typedef struct -{ - int i; - unsigned long *layer_differences; -} CoglPipelineFlushLayerState; - -static gboolean -flush_layers_common_gl_state_cb (CoglPipelineLayer *layer, void *user_data) -{ - CoglPipelineFlushLayerState *flush_state = user_data; - int unit_index = flush_state->i; - CoglTextureUnit *unit = _cogl_get_texture_unit (unit_index); - unsigned long layers_difference = - flush_state->layer_differences[unit_index]; - - _COGL_GET_CONTEXT (ctx, FALSE); - - /* There may not be enough texture units so we can bail out if - * that's the case... - */ - if (G_UNLIKELY (unit_index >= get_max_activateable_texture_units ())) - { - static gboolean shown_warning = FALSE; - - if (!shown_warning) - { - g_warning ("Your hardware does not have enough texture units" - "to handle this many texture layers"); - shown_warning = TRUE; - } - return FALSE; - } - - if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA) - { - CoglTexture *texture = _cogl_pipeline_layer_get_texture_real (layer); - GLuint gl_texture; - GLenum gl_target; - - if (texture == NULL) - texture = COGL_TEXTURE (ctx->default_gl_texture_2d_tex); - - cogl_texture_get_gl_texture (texture, - &gl_texture, - &gl_target); - - _cogl_set_active_texture_unit (unit_index); - - /* NB: There are several Cogl components and some code in - * Clutter that will temporarily bind arbitrary GL textures to - * query and modify texture object parameters. If you look at - * _cogl_bind_gl_texture_transient() you can see we make sure - * that such code always binds to texture unit 1 which means we - * can't rely on the unit->gl_texture state if unit->index == 1. - * - * Because texture unit 1 is a bit special we actually defer any - * necessary glBindTexture for it until the end of - * _cogl_pipeline_flush_gl_state(). - * - * NB: we get notified whenever glDeleteTextures is used (see - * _cogl_delete_gl_texture()) where we invalidate - * unit->gl_texture references to deleted textures so it's safe - * to compare unit->gl_texture with gl_texture. (Without the - * hook it would be possible to delete a GL texture and create a - * new one with the same name and comparing unit->gl_texture and - * gl_texture wouldn't detect that.) - * - * NB: for foreign textures we don't know how the deletion of - * the GL texture objects correspond to the deletion of the - * CoglTextures so if there was previously a foreign texture - * associated with the texture unit then we can't assume that we - * aren't seeing a recycled texture name so we have to bind. - */ - if (unit->gl_texture != gl_texture) - { - if (unit_index == 1) - unit->dirty_gl_texture = TRUE; - else - GE (ctx, glBindTexture (gl_target, gl_texture)); - unit->gl_texture = gl_texture; - unit->gl_target = gl_target; - } - - /* The texture_storage_changed boolean indicates if the - * CoglTexture's underlying GL texture storage has changed since - * it was flushed to the texture unit. We've just flushed the - * latest state so we can reset this. */ - unit->texture_storage_changed = FALSE; - } - - if ((layers_difference & COGL_PIPELINE_LAYER_STATE_SAMPLER) && - _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS)) - { - const CoglSamplerCacheEntry *sampler_state; - - sampler_state = _cogl_pipeline_layer_get_sampler_state (layer); - - GE( ctx, glBindSampler (unit_index, sampler_state->sampler_object) ); - } - - cogl_object_ref (layer); - if (unit->layer != NULL) - cogl_object_unref (unit->layer); - - unit->layer = layer; - unit->layer_changes_since_flush = 0; - - flush_state->i++; - - return TRUE; -} - -static void -_cogl_pipeline_flush_common_gl_state (CoglPipeline *pipeline, - unsigned long pipelines_difference, - unsigned long *layer_differences, - gboolean with_color_attrib) -{ - CoglPipelineFlushLayerState state; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - _cogl_pipeline_flush_color_blend_alpha_depth_state (pipeline, - pipelines_difference, - with_color_attrib); - - state.i = 0; - state.layer_differences = layer_differences; - _cogl_pipeline_foreach_layer_internal (pipeline, - flush_layers_common_gl_state_cb, - &state); -} - -/* Re-assert the layer's wrap modes on the given CoglTexture. - * - * Note: we don't simply forward the wrap modes to layer->texture - * since the actual texture being used may have been overridden. - */ -static void -_cogl_pipeline_layer_forward_wrap_modes (CoglPipelineLayer *layer, - CoglTexture *texture) -{ - CoglSamplerCacheWrapMode wrap_mode_s, wrap_mode_t; - GLenum gl_wrap_mode_s, gl_wrap_mode_t; - - if (texture == NULL) - return; - - _cogl_pipeline_layer_get_wrap_modes (layer, - &wrap_mode_s, - &wrap_mode_t); - - /* Update the wrap mode on the texture object. The texture backend - should cache the value so that it will be a no-op if the object - already has the same wrap mode set. The backend is best placed to - do this because it knows how many of the coordinates will - actually be used (ie, a 1D texture only cares about the 's' - coordinate but a 3D texture would use all three). GL uses the - wrap mode as part of the texture object state but we are - pretending it's part of the per-layer environment state. This - will break if the application tries to use different modes in - different layers using the same texture. */ - - if (wrap_mode_s == COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC) - gl_wrap_mode_s = GL_CLAMP_TO_EDGE; - else - gl_wrap_mode_s = wrap_mode_s; - - if (wrap_mode_t == COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC) - gl_wrap_mode_t = GL_CLAMP_TO_EDGE; - else - gl_wrap_mode_t = wrap_mode_t; - - _cogl_texture_gl_flush_legacy_texobj_wrap_modes (texture, - gl_wrap_mode_s, - gl_wrap_mode_t); -} - -void -_cogl_sampler_gl_init (CoglContext *context, CoglSamplerCacheEntry *entry) -{ - if (_cogl_has_private_feature (context, - COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS)) - { - GE( context, glGenSamplers (1, &entry->sampler_object) ); - - GE( context, glSamplerParameteri (entry->sampler_object, - GL_TEXTURE_MIN_FILTER, - entry->min_filter) ); - GE( context, glSamplerParameteri (entry->sampler_object, - GL_TEXTURE_MAG_FILTER, - entry->mag_filter) ); - - GE (context, glSamplerParameteri (entry->sampler_object, - GL_TEXTURE_WRAP_S, - entry->wrap_mode_s) ); - GE (context, glSamplerParameteri (entry->sampler_object, - GL_TEXTURE_WRAP_T, - entry->wrap_mode_t) ); - } - else - { - CoglGLContext *gl_context = context->driver_context; - - /* If sampler objects aren't supported then we'll invent a - unique number so that pipelines can still compare the - unique state just by comparing the sampler object - numbers */ - entry->sampler_object = gl_context->next_fake_sampler_object_number++; - } -} - -void -_cogl_sampler_gl_free (CoglContext *context, CoglSamplerCacheEntry *entry) -{ - if (_cogl_has_private_feature (context, - COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS)) - GE( context, glDeleteSamplers (1, &entry->sampler_object) ); -} - -/* OpenGL associates the min/mag filters and repeat modes with the - * texture object not the texture unit so we always have to re-assert - * the filter and repeat modes whenever we use a texture since it may - * be referenced by multiple pipelines with different modes. - * - * This function is bypassed in favour of sampler objects if - * GL_ARB_sampler_objects is advertised. This fallback won't work if - * the same texture is bound to multiple layers with different sampler - * state. - */ -static void -foreach_texture_unit_update_filter_and_wrap_modes (void) -{ - int i; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - CoglGLContext *glctx = _cogl_driver_gl_context(ctx); - - for (i = 0; i < glctx->texture_units->len; i++) - { - CoglTextureUnit *unit = - &g_array_index (glctx->texture_units, CoglTextureUnit, i); - - if (unit->layer) - { - CoglTexture *texture = _cogl_pipeline_layer_get_texture (unit->layer); - - if (texture != NULL) - { - CoglPipelineFilter min; - CoglPipelineFilter mag; - - _cogl_pipeline_layer_get_filters (unit->layer, &min, &mag); - _cogl_texture_gl_flush_legacy_texobj_filters (texture, min, mag); - - _cogl_pipeline_layer_forward_wrap_modes (unit->layer, texture); - } - } - } -} - -typedef struct -{ - int i; - unsigned long *layer_differences; -} CoglPipelineCompareLayersState; - -static gboolean -compare_layer_differences_cb (CoglPipelineLayer *layer, void *user_data) -{ - CoglPipelineCompareLayersState *state = user_data; - CoglTextureUnit *unit = _cogl_get_texture_unit (state->i); - - if (unit->layer == layer) - state->layer_differences[state->i] = unit->layer_changes_since_flush; - else if (unit->layer) - { - state->layer_differences[state->i] = unit->layer_changes_since_flush; - state->layer_differences[state->i] |= - _cogl_pipeline_layer_compare_differences (layer, unit->layer); - } - else - state->layer_differences[state->i] = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE; - - /* XXX: There is always a possibility that a CoglTexture's - * underlying GL texture storage has been changed since it was last - * bound to a texture unit which is why we have a callback into - * _cogl_pipeline_texture_storage_change_notify whenever a textures - * underlying GL texture storage changes which will set the - * unit->texture_intern_changed flag. If we see that's been set here - * then we force an update of the texture state... - */ - if (unit->texture_storage_changed) - state->layer_differences[state->i] |= - COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA; - - state->i++; - - return TRUE; -} - -typedef struct -{ - CoglFramebuffer *framebuffer; - const CoglPipelineVertend *vertend; - const CoglPipelineFragend *fragend; - CoglPipeline *pipeline; - unsigned long *layer_differences; - gboolean error_adding_layer; - gboolean added_layer; -} CoglPipelineAddLayerState; - -static gboolean -vertend_add_layer_cb (CoglPipelineLayer *layer, - void *user_data) -{ - CoglPipelineAddLayerState *state = user_data; - const CoglPipelineVertend *vertend = state->vertend; - CoglPipeline *pipeline = state->pipeline; - int unit_index = _cogl_pipeline_layer_get_unit_index (layer); - - /* Either generate per layer code snippets or setup the - * fixed function glTexEnv for each layer... */ - if (G_LIKELY (vertend->add_layer (pipeline, - layer, - state->layer_differences[unit_index], - state->framebuffer))) - state->added_layer = TRUE; - else - { - state->error_adding_layer = TRUE; - return FALSE; - } - - return TRUE; -} - -static gboolean -fragend_add_layer_cb (CoglPipelineLayer *layer, - void *user_data) -{ - CoglPipelineAddLayerState *state = user_data; - const CoglPipelineFragend *fragend = state->fragend; - CoglPipeline *pipeline = state->pipeline; - int unit_index = _cogl_pipeline_layer_get_unit_index (layer); - - /* Either generate per layer code snippets or setup the - * fixed function glTexEnv for each layer... */ - if (G_LIKELY (fragend->add_layer (pipeline, - layer, - state->layer_differences[unit_index]))) - state->added_layer = TRUE; - else - { - state->error_adding_layer = TRUE; - return FALSE; - } - - return TRUE; -} - -/* - * _cogl_pipeline_flush_gl_state: - * - * Details of override options: - * ->fallback_mask: is a bitmask of the pipeline layers that need to be - * replaced with the default, fallback textures. The fallback textures are - * fully transparent textures so they hopefully won't contribute to the - * texture combining. - * - * The intention of fallbacks is to try and preserve - * the number of layers the user is expecting so that texture coordinates - * they gave will mostly still correspond to the textures they intended, and - * have a fighting chance of looking close to their originally intended - * result. - * - * ->disable_mask: is a bitmask of the pipeline layers that will simply have - * texturing disabled. It's only really intended for disabling all layers - * > X; i.e. we'd expect to see a contiguous run of 0 starting from the LSB - * and at some point the remaining bits flip to 1. It might work to disable - * arbitrary layers; though I'm not sure a.t.m how OpenGL would take to - * that. - * - * The intention of the disable_mask is for emitting geometry when the user - * hasn't supplied enough texture coordinates for all the layers and it's - * not possible to auto generate default texture coordinates for those - * layers. - * - * ->layer0_override_texture: forcibly tells us to bind this GL texture name for - * layer 0 instead of plucking the gl_texture from the CoglTexture of layer - * 0. - * - * The intention of this is for any primitives that supports sliced textures. - * The code will can iterate each of the slices and re-flush the pipeline - * forcing the GL texture of each slice in turn. - * - * ->wrap_mode_overrides: overrides the wrap modes set on each - * layer. This is used to implement the automatic wrap mode. - * - * XXX: It might also help if we could specify a texture matrix for code - * dealing with slicing that would be multiplied with the users own matrix. - * - * Normally texture coords in the range [0, 1] refer to the extents of the - * texture, but when your GL texture represents a slice of the real texture - * (from the users POV) then a texture matrix would be a neat way of - * transforming the mapping for each slice. - * - * Currently for textured rectangles we manually calculate the texture - * coords for each slice based on the users given coords, but this solution - * isn't ideal. - */ -void -_cogl_pipeline_flush_gl_state (CoglContext *ctx, - CoglPipeline *pipeline, - CoglFramebuffer *framebuffer, - gboolean with_color_attrib, - gboolean unknown_color_alpha) -{ - CoglPipeline *current_pipeline = ctx->current_pipeline; - unsigned long pipelines_difference; - int n_layers; - unsigned long *layer_differences; - CoglTextureUnit *unit1; - const CoglPipelineProgend *progend; - - COGL_STATIC_TIMER (pipeline_flush_timer, - "Mainloop", /* parent */ - "Material Flush", - "The time spent flushing material state", - 0 /* no application private data */); - - COGL_TIMER_START (_cogl_uprof_context, pipeline_flush_timer); - - /* Bail out asap if we've been asked to re-flush the already current - * pipeline and we can see the pipeline hasn't changed */ - if (current_pipeline == pipeline && - ctx->current_pipeline_age == pipeline->age && - ctx->current_pipeline_with_color_attrib == with_color_attrib && - ctx->current_pipeline_unknown_color_alpha == unknown_color_alpha) - goto done; - else - { - /* Update derived state (currently just the 'real_blend_enable' - * state) and determine a mask of state that differs between the - * current pipeline and the one we are flushing. - * - * Note updating the derived state is done before doing any - * pipeline comparisons so that we can correctly compare the - * 'real_blend_enable' state itself. - */ - - if (current_pipeline == pipeline) - { - pipelines_difference = ctx->current_pipeline_changes_since_flush; - - if (pipelines_difference & COGL_PIPELINE_STATE_AFFECTS_BLENDING || - pipeline->unknown_color_alpha != unknown_color_alpha) - { - gboolean save_real_blend_enable = pipeline->real_blend_enable; - - _cogl_pipeline_update_real_blend_enable (pipeline, - unknown_color_alpha); - - if (save_real_blend_enable != pipeline->real_blend_enable) - pipelines_difference |= COGL_PIPELINE_STATE_REAL_BLEND_ENABLE; - } - } - else if (current_pipeline) - { - pipelines_difference = ctx->current_pipeline_changes_since_flush; - - _cogl_pipeline_update_real_blend_enable (pipeline, - unknown_color_alpha); - - pipelines_difference |= - _cogl_pipeline_compare_differences (ctx->current_pipeline, - pipeline); - } - else - { - _cogl_pipeline_update_real_blend_enable (pipeline, - unknown_color_alpha); - - pipelines_difference = COGL_PIPELINE_STATE_ALL; - } - } - - /* Get a layer_differences mask for each layer to be flushed */ - n_layers = cogl_pipeline_get_n_layers (pipeline); - if (n_layers) - { - CoglPipelineCompareLayersState state; - layer_differences = g_alloca (sizeof (unsigned long) * n_layers); - memset (layer_differences, 0, sizeof (unsigned long) * n_layers); - state.i = 0; - state.layer_differences = layer_differences; - _cogl_pipeline_foreach_layer_internal (pipeline, - compare_layer_differences_cb, - &state); - } - else - layer_differences = NULL; - - /* First flush everything that's the same regardless of which - * pipeline backend is being used... - * - * 1) top level state: - * glColor (or skip if a vertex attribute is being used for color) - * blend state - * alpha test state (except for GLES 2.0) - * - * 2) then foreach layer: - * determine gl_target/gl_texture - * bind texture - * - * Note: After _cogl_pipeline_flush_common_gl_state you can expect - * all state of the layers corresponding texture unit to be - * updated. - */ - _cogl_pipeline_flush_common_gl_state (pipeline, - pipelines_difference, - layer_differences, - with_color_attrib); - - /* Now flush the fragment, vertex and program state according to the - * current progend backend. - * - * Note: Some backends may not support the current pipeline - * configuration and in that case it will report and error and we - * will look for a different backend. - * - * NB: if pipeline->progend != COGL_PIPELINE_PROGEND_UNDEFINED then - * we have previously managed to successfully flush this pipeline - * with the given progend so we will simply use that to avoid - * fallback code paths. - */ - - do - { - const CoglPipelineVertend *vertend; - const CoglPipelineFragend *fragend; - CoglPipelineAddLayerState state; - - progend = _cogl_pipeline_progend; - - if (G_UNLIKELY (!progend->start (pipeline))) - continue; - - vertend = _cogl_pipeline_vertend; - - vertend->start (pipeline, - n_layers, - pipelines_difference); - - state.framebuffer = framebuffer; - state.vertend = vertend; - state.pipeline = pipeline; - state.layer_differences = layer_differences; - state.error_adding_layer = FALSE; - state.added_layer = FALSE; - - _cogl_pipeline_foreach_layer_internal (pipeline, - vertend_add_layer_cb, - &state); - - if (G_UNLIKELY (state.error_adding_layer)) - continue; - - if (G_UNLIKELY (!vertend->end (pipeline, pipelines_difference))) - continue; - - /* Now prepare the fragment processing state (fragend) - * - * NB: We can't combine the setup of the vertend and fragend - * since the backends that do code generation share - * ctx->codegen_source_buffer as a scratch buffer. - */ - - fragend = _cogl_pipeline_fragend; - state.fragend = fragend; - - fragend->start (pipeline, - n_layers, - pipelines_difference); - - _cogl_pipeline_foreach_layer_internal (pipeline, - fragend_add_layer_cb, - &state); - - if (G_UNLIKELY (state.error_adding_layer)) - continue; - - if (G_UNLIKELY (!fragend->end (pipeline, pipelines_difference))) - continue; - - if (progend->end) - progend->end (pipeline, pipelines_difference); - break; - } - while (0); - - /* FIXME: This reference is actually resulting in lots of - * copy-on-write reparenting because one-shot pipelines end up - * living for longer than necessary and so any later modification of - * the parent will cause a copy-on-write. - * - * XXX: The issue should largely go away when we switch to using - * weak pipelines for overrides. - */ - cogl_object_ref (pipeline); - if (ctx->current_pipeline != NULL) - cogl_object_unref (ctx->current_pipeline); - ctx->current_pipeline = pipeline; - ctx->current_pipeline_changes_since_flush = 0; - ctx->current_pipeline_with_color_attrib = with_color_attrib; - ctx->current_pipeline_unknown_color_alpha = unknown_color_alpha; - ctx->current_pipeline_age = pipeline->age; - -done: - - progend = _cogl_pipeline_progend; - - /* We can't assume the color will be retained between flushes when - * using the glsl progend because the generic attribute values are - * not stored as part of the program object so they could be - * overridden by any attribute changes in another program */ - if (!with_color_attrib) - { - int attribute; - CoglPipeline *authority = - _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR); - int name_index = COGL_ATTRIBUTE_COLOR_NAME_INDEX; - - attribute = - _cogl_pipeline_progend_glsl_get_attrib_location (pipeline, name_index); - if (attribute != -1) - GE (ctx, - glVertexAttrib4f (attribute, - cogl_color_get_red_float (&authority->color), - cogl_color_get_green_float (&authority->color), - cogl_color_get_blue_float (&authority->color), - cogl_color_get_alpha_float (&authority->color))); - } - - /* Give the progend a chance to update any uniforms that might not - * depend on the material state. This is used on GLES2 to update the - * matrices */ - if (progend->pre_paint) - progend->pre_paint (pipeline, framebuffer); - - /* Handle the fact that OpenGL associates texture filter and wrap - * modes with the texture objects not the texture units... */ - if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS)) - foreach_texture_unit_update_filter_and_wrap_modes (); - - /* If this pipeline has more than one layer then we always need - * to make sure we rebind the texture for unit 1. - * - * NB: various components of Cogl may temporarily bind arbitrary - * textures to texture unit 1 so they can query and modify texture - * object parameters. cogl-pipeline.c (See - * _cogl_bind_gl_texture_transient) - */ - unit1 = _cogl_get_texture_unit (1); - if (cogl_pipeline_get_n_layers (pipeline) > 1 && unit1->dirty_gl_texture) - { - _cogl_set_active_texture_unit (1); - GE (ctx, glBindTexture (unit1->gl_target, unit1->gl_texture)); - unit1->dirty_gl_texture = FALSE; - } - - COGL_TIMER_STOP (_cogl_uprof_context, pipeline_flush_timer); -} - -void -_cogl_gl_set_uniform (CoglContext *ctx, - GLint location, - const CoglBoxedValue *value) -{ - switch (value->type) - { - case COGL_BOXED_NONE: - break; - - case COGL_BOXED_INT: - { - const int *ptr; - - if (value->count == 1) - ptr = value->v.int_value; - else - ptr = value->v.int_array; - - switch (value->size) - { - case 1: - GE( ctx, glUniform1iv (location, value->count, ptr) ); - break; - case 2: - GE( ctx, glUniform2iv (location, value->count, ptr) ); - break; - case 3: - GE( ctx, glUniform3iv (location, value->count, ptr) ); - break; - case 4: - GE( ctx, glUniform4iv (location, value->count, ptr) ); - break; - } - } - break; - - case COGL_BOXED_FLOAT: - { - const float *ptr; - - if (value->count == 1) - ptr = value->v.float_value; - else - ptr = value->v.float_array; - - switch (value->size) - { - case 1: - GE( ctx, glUniform1fv (location, value->count, ptr) ); - break; - case 2: - GE( ctx, glUniform2fv (location, value->count, ptr) ); - break; - case 3: - GE( ctx, glUniform3fv (location, value->count, ptr) ); - break; - case 4: - GE( ctx, glUniform4fv (location, value->count, ptr) ); - break; - } - } - break; - - case COGL_BOXED_MATRIX: - { - const float *ptr; - - if (value->count == 1) - ptr = value->v.matrix; - else - ptr = value->v.float_array; - - switch (value->size) - { - case 2: - GE( ctx, glUniformMatrix2fv (location, value->count, - FALSE, ptr) ); - break; - case 3: - GE( ctx, glUniformMatrix3fv (location, value->count, - FALSE, ptr) ); - break; - case 4: - GE( ctx, glUniformMatrix4fv (location, value->count, - FALSE, ptr) ); - break; - } - } - break; - } -} diff --git a/cogl/cogl/driver/gl/cogl-pipeline-progend-glsl-private.h b/cogl/cogl/driver/gl/cogl-pipeline-progend-glsl-private.h deleted file mode 100644 index d57519b80..000000000 --- a/cogl/cogl/driver/gl/cogl-pipeline-progend-glsl-private.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2010 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Neil Roberts <neil@linux.intel.com> - */ - -#ifndef __COGL_PIPELINE_PROGEND_GLSL_PRIVATE_H -#define __COGL_PIPELINE_PROGEND_GLSL_PRIVATE_H - -#include "cogl-pipeline-private.h" -#include "cogl-attribute-private.h" - -extern const CoglPipelineProgend _cogl_pipeline_glsl_progend; - -int -_cogl_pipeline_progend_glsl_get_attrib_location (CoglPipeline *pipeline, - int name_index); - -#endif /* __COGL_PIPELINE_PROGEND_GLSL_PRIVATE_H */ - diff --git a/cogl/cogl/driver/gl/cogl-pipeline-progend-glsl.c b/cogl/cogl/driver/gl/cogl-pipeline-progend-glsl.c deleted file mode 100644 index 9d94f12ce..000000000 --- a/cogl/cogl/driver/gl/cogl-pipeline-progend-glsl.c +++ /dev/null @@ -1,1145 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2010 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Neil Roberts <neil@linux.intel.com> - */ - -#include "cogl-config.h" - -#include <string.h> - -#include "cogl-util.h" -#include "cogl-context-private.h" -#include "cogl-pipeline-private.h" -#include "cogl-offscreen.h" -#include "driver/gl/cogl-util-gl-private.h" -#include "driver/gl/cogl-pipeline-opengl-private.h" - -#include "cogl-context-private.h" -#include "cogl-object-private.h" -#include "cogl-pipeline-cache.h" -#include "cogl-pipeline-state-private.h" -#include "cogl-attribute-private.h" -#include "cogl-framebuffer-private.h" -#include "driver/gl/cogl-pipeline-fragend-glsl-private.h" -#include "driver/gl/cogl-pipeline-vertend-glsl-private.h" -#include "driver/gl/cogl-pipeline-progend-glsl-private.h" -#include "deprecated/cogl-program-private.h" - -/* These are used to generalise updating some uniforms that are - required when building for drivers missing some fixed function - state that we use */ - -typedef void (* UpdateUniformFunc) (CoglPipeline *pipeline, - int uniform_location, - void *getter_func); - -static void update_float_uniform (CoglPipeline *pipeline, - int uniform_location, - void *getter_func); - -typedef struct -{ - const char *uniform_name; - void *getter_func; - UpdateUniformFunc update_func; - CoglPipelineState change; -} BuiltinUniformData; - -static BuiltinUniformData builtin_uniforms[] = - { - { "cogl_point_size_in", - cogl_pipeline_get_point_size, update_float_uniform, - COGL_PIPELINE_STATE_POINT_SIZE }, - { "_cogl_alpha_test_ref", - cogl_pipeline_get_alpha_test_reference, update_float_uniform, - COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE }, - }; - -const CoglPipelineProgend _cogl_pipeline_glsl_progend; - -typedef struct _UnitState -{ - unsigned int dirty_combine_constant:1; - unsigned int dirty_texture_matrix:1; - - GLint combine_constant_uniform; - - GLint texture_matrix_uniform; -} UnitState; - -typedef struct -{ - unsigned int ref_count; - - /* Age that the user program had last time we generated a GL - program. If it's different then we need to relink the program */ - unsigned int user_program_age; - - GLuint program; - - unsigned long dirty_builtin_uniforms; - GLint builtin_uniform_locations[G_N_ELEMENTS (builtin_uniforms)]; - - GLint modelview_uniform; - GLint projection_uniform; - GLint mvp_uniform; - - CoglMatrixEntryCache projection_cache; - CoglMatrixEntryCache modelview_cache; - - /* We need to track the last pipeline that the program was used with - * so know if we need to update all of the uniforms */ - CoglPipeline *last_used_for_pipeline; - - /* Array of GL uniform locations indexed by Cogl's uniform - location. We are careful only to allocated this array if a custom - uniform is actually set */ - GArray *uniform_locations; - - /* Array of attribute locations. */ - GArray *attribute_locations; - - /* The 'flip' uniform is used to flip the geometry upside-down when - the framebuffer requires it only when there are vertex - snippets. Otherwise this is achieved using the projection - matrix */ - GLint flip_uniform; - int flushed_flip_state; - - UnitState *unit_state; - - CoglPipelineCacheEntry *cache_entry; -} CoglPipelineProgramState; - -static CoglUserDataKey program_state_key; - -static CoglPipelineProgramState * -get_program_state (CoglPipeline *pipeline) -{ - return cogl_object_get_user_data (COGL_OBJECT (pipeline), &program_state_key); -} - -#define UNIFORM_LOCATION_UNKNOWN -2 - -#define ATTRIBUTE_LOCATION_UNKNOWN -2 - -/* Under GLES2 the vertex attribute API needs to query the attribute - numbers because it can't used the fixed function API to set the - builtin attributes. We cache the attributes here because the - progend knows when the program is changed so it can clear the - cache. This should always be called after the pipeline is flushed - so they can assert that the gl program is valid */ - -/* All attributes names get internally mapped to a global set of - * sequential indices when they are setup which we need to need to - * then be able to map to a GL attribute location once we have - * a linked GLSL program */ - -int -_cogl_pipeline_progend_glsl_get_attrib_location (CoglPipeline *pipeline, - int name_index) -{ - CoglPipelineProgramState *program_state = get_program_state (pipeline); - int *locations; - - _COGL_GET_CONTEXT (ctx, -1); - - g_return_val_if_fail (program_state != NULL, -1); - g_return_val_if_fail (program_state->program != 0, -1); - - if (G_UNLIKELY (program_state->attribute_locations == NULL)) - program_state->attribute_locations = - g_array_new (FALSE, FALSE, sizeof (int)); - - if (G_UNLIKELY (program_state->attribute_locations->len <= name_index)) - { - int i = program_state->attribute_locations->len; - g_array_set_size (program_state->attribute_locations, name_index + 1); - for (; i < program_state->attribute_locations->len; i++) - g_array_index (program_state->attribute_locations, int, i) - = ATTRIBUTE_LOCATION_UNKNOWN; - } - - locations = &g_array_index (program_state->attribute_locations, int, 0); - - if (locations[name_index] == ATTRIBUTE_LOCATION_UNKNOWN) - { - CoglAttributeNameState *name_state = - g_array_index (ctx->attribute_name_index_map, - CoglAttributeNameState *, name_index); - - g_return_val_if_fail (name_state != NULL, 0); - - GE_RET( locations[name_index], - ctx, glGetAttribLocation (program_state->program, - name_state->name) ); - } - - return locations[name_index]; -} - -static void -clear_attribute_cache (CoglPipelineProgramState *program_state) -{ - if (program_state->attribute_locations) - { - g_array_free (program_state->attribute_locations, TRUE); - program_state->attribute_locations = NULL; - } -} - -static void -clear_flushed_matrix_stacks (CoglPipelineProgramState *program_state) -{ - _cogl_matrix_entry_cache_destroy (&program_state->projection_cache); - _cogl_matrix_entry_cache_init (&program_state->projection_cache); - _cogl_matrix_entry_cache_destroy (&program_state->modelview_cache); - _cogl_matrix_entry_cache_init (&program_state->modelview_cache); -} - -static CoglPipelineProgramState * -program_state_new (int n_layers, - CoglPipelineCacheEntry *cache_entry) -{ - CoglPipelineProgramState *program_state; - - program_state = g_new0 (CoglPipelineProgramState, 1); - program_state->ref_count = 1; - program_state->program = 0; - program_state->unit_state = g_new (UnitState, n_layers); - program_state->uniform_locations = NULL; - program_state->attribute_locations = NULL; - program_state->cache_entry = cache_entry; - _cogl_matrix_entry_cache_init (&program_state->modelview_cache); - _cogl_matrix_entry_cache_init (&program_state->projection_cache); - - return program_state; -} - -static void -destroy_program_state (void *user_data, - void *instance) -{ - CoglPipelineProgramState *program_state = user_data; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* If the program state was last used for this pipeline then clear - it so that if same address gets used again for a new pipeline - then we won't think it's the same pipeline and avoid updating the - uniforms */ - if (program_state->last_used_for_pipeline == instance) - program_state->last_used_for_pipeline = NULL; - - if (program_state->cache_entry && - program_state->cache_entry->pipeline != instance) - program_state->cache_entry->usage_count--; - - if (--program_state->ref_count == 0) - { - clear_attribute_cache (program_state); - - _cogl_matrix_entry_cache_destroy (&program_state->projection_cache); - _cogl_matrix_entry_cache_destroy (&program_state->modelview_cache); - - if (program_state->program) - GE( ctx, glDeleteProgram (program_state->program) ); - - g_free (program_state->unit_state); - - if (program_state->uniform_locations) - g_array_free (program_state->uniform_locations, TRUE); - - g_free (program_state); - } -} - -static void -set_program_state (CoglPipeline *pipeline, - CoglPipelineProgramState *program_state) -{ - if (program_state) - { - program_state->ref_count++; - - /* If we're not setting the state on the template pipeline then - * mark it as a usage of the pipeline cache entry */ - if (program_state->cache_entry && - program_state->cache_entry->pipeline != pipeline) - program_state->cache_entry->usage_count++; - } - - _cogl_object_set_user_data (COGL_OBJECT (pipeline), - &program_state_key, - program_state, - destroy_program_state); -} - -static void -dirty_program_state (CoglPipeline *pipeline) -{ - cogl_object_set_user_data (COGL_OBJECT (pipeline), - &program_state_key, - NULL, - NULL); -} - -static void -link_program (GLint gl_program) -{ - GLint link_status; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - GE( ctx, glLinkProgram (gl_program) ); - - GE( ctx, glGetProgramiv (gl_program, GL_LINK_STATUS, &link_status) ); - - if (!link_status) - { - GLint log_length; - GLsizei out_log_length; - char *log; - - GE( ctx, glGetProgramiv (gl_program, GL_INFO_LOG_LENGTH, &log_length) ); - - log = g_malloc (log_length); - - GE( ctx, glGetProgramInfoLog (gl_program, log_length, - &out_log_length, log) ); - - g_warning ("Failed to link GLSL program:\n%.*s\n", - log_length, log); - - g_free (log); - } -} - -typedef struct -{ - int unit; - GLuint gl_program; - gboolean update_all; - CoglPipelineProgramState *program_state; -} UpdateUniformsState; - -static gboolean -get_uniform_cb (CoglPipeline *pipeline, - int layer_index, - void *user_data) -{ - UpdateUniformsState *state = user_data; - CoglPipelineProgramState *program_state = state->program_state; - UnitState *unit_state = &program_state->unit_state[state->unit]; - GLint uniform_location; - - _COGL_GET_CONTEXT (ctx, FALSE); - - /* We can reuse the source buffer to create the uniform name because - the program has now been linked */ - g_string_set_size (ctx->codegen_source_buffer, 0); - g_string_append_printf (ctx->codegen_source_buffer, - "cogl_sampler%i", layer_index); - - GE_RET( uniform_location, - ctx, glGetUniformLocation (state->gl_program, - ctx->codegen_source_buffer->str) ); - - /* We can set the uniform immediately because the samplers are the - unit index not the texture object number so it will never - change. Unfortunately GL won't let us use a constant instead of a - uniform */ - if (uniform_location != -1) - GE( ctx, glUniform1i (uniform_location, state->unit) ); - - g_string_set_size (ctx->codegen_source_buffer, 0); - g_string_append_printf (ctx->codegen_source_buffer, - "_cogl_layer_constant_%i", layer_index); - - GE_RET( uniform_location, - ctx, glGetUniformLocation (state->gl_program, - ctx->codegen_source_buffer->str) ); - - unit_state->combine_constant_uniform = uniform_location; - - g_string_set_size (ctx->codegen_source_buffer, 0); - g_string_append_printf (ctx->codegen_source_buffer, - "cogl_texture_matrix[%i]", layer_index); - - GE_RET( uniform_location, - ctx, glGetUniformLocation (state->gl_program, - ctx->codegen_source_buffer->str) ); - - unit_state->texture_matrix_uniform = uniform_location; - - state->unit++; - - return TRUE; -} - -static gboolean -update_constants_cb (CoglPipeline *pipeline, - int layer_index, - void *user_data) -{ - UpdateUniformsState *state = user_data; - CoglPipelineProgramState *program_state = state->program_state; - UnitState *unit_state = &program_state->unit_state[state->unit++]; - - _COGL_GET_CONTEXT (ctx, FALSE); - - if (unit_state->combine_constant_uniform != -1 && - (state->update_all || unit_state->dirty_combine_constant)) - { - float constant[4]; - _cogl_pipeline_get_layer_combine_constant (pipeline, - layer_index, - constant); - GE (ctx, glUniform4fv (unit_state->combine_constant_uniform, - 1, constant)); - unit_state->dirty_combine_constant = FALSE; - } - - if (unit_state->texture_matrix_uniform != -1 && - (state->update_all || unit_state->dirty_texture_matrix)) - { - const graphene_matrix_t *matrix; - float array[16]; - - matrix = _cogl_pipeline_get_layer_matrix (pipeline, layer_index); - graphene_matrix_to_float (matrix, array); - GE (ctx, glUniformMatrix4fv (unit_state->texture_matrix_uniform, - 1, FALSE, array)); - unit_state->dirty_texture_matrix = FALSE; - } - - return TRUE; -} - -static void -update_builtin_uniforms (CoglContext *context, - CoglPipeline *pipeline, - GLuint gl_program, - CoglPipelineProgramState *program_state) -{ - int i; - - if (program_state->dirty_builtin_uniforms == 0) - return; - - for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++) - if ((program_state->dirty_builtin_uniforms & (1 << i)) && - program_state->builtin_uniform_locations[i] != -1) - builtin_uniforms[i].update_func (pipeline, - program_state - ->builtin_uniform_locations[i], - builtin_uniforms[i].getter_func); - - program_state->dirty_builtin_uniforms = 0; -} - -typedef struct -{ - CoglPipelineProgramState *program_state; - unsigned long *uniform_differences; - int n_differences; - CoglContext *ctx; - const CoglBoxedValue *values; - int value_index; -} FlushUniformsClosure; - -static gboolean -flush_uniform_cb (int uniform_num, void *user_data) -{ - FlushUniformsClosure *data = user_data; - - if (COGL_FLAGS_GET (data->uniform_differences, uniform_num)) - { - GArray *uniform_locations; - GLint uniform_location; - - if (data->program_state->uniform_locations == NULL) - data->program_state->uniform_locations = - g_array_new (FALSE, FALSE, sizeof (GLint)); - - uniform_locations = data->program_state->uniform_locations; - - if (uniform_locations->len <= uniform_num) - { - unsigned int old_len = uniform_locations->len; - - g_array_set_size (uniform_locations, uniform_num + 1); - - while (old_len <= uniform_num) - { - g_array_index (uniform_locations, GLint, old_len) = - UNIFORM_LOCATION_UNKNOWN; - old_len++; - } - } - - uniform_location = g_array_index (uniform_locations, GLint, uniform_num); - - if (uniform_location == UNIFORM_LOCATION_UNKNOWN) - { - const char *uniform_name = - g_ptr_array_index (data->ctx->uniform_names, uniform_num); - - uniform_location = - data->ctx->glGetUniformLocation (data->program_state->program, - uniform_name); - g_array_index (uniform_locations, GLint, uniform_num) = - uniform_location; - } - - if (uniform_location != -1) - _cogl_boxed_value_set_uniform (data->ctx, - uniform_location, - data->values + data->value_index); - - data->n_differences--; - COGL_FLAGS_SET (data->uniform_differences, uniform_num, FALSE); - } - - data->value_index++; - - return data->n_differences > 0; -} - -static void -_cogl_pipeline_progend_glsl_flush_uniforms (CoglPipeline *pipeline, - CoglPipelineProgramState * - program_state, - GLuint gl_program, - gboolean program_changed) -{ - CoglPipelineUniformsState *uniforms_state; - FlushUniformsClosure data; - int n_uniform_longs; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS) - uniforms_state = &pipeline->big_state->uniforms_state; - else - uniforms_state = NULL; - - data.program_state = program_state; - data.ctx = ctx; - - n_uniform_longs = COGL_FLAGS_N_LONGS_FOR_SIZE (ctx->n_uniform_names); - - data.uniform_differences = g_newa (unsigned long, n_uniform_longs); - - /* Try to find a common ancestor for the values that were already - flushed on the pipeline that this program state was last used for - so we can avoid flushing those */ - - if (program_changed || program_state->last_used_for_pipeline == NULL) - { - if (program_changed) - { - /* The program has changed so all of the uniform locations - are invalid */ - if (program_state->uniform_locations) - g_array_set_size (program_state->uniform_locations, 0); - } - - /* We need to flush everything so mark all of the uniforms as - dirty */ - memset (data.uniform_differences, 0xff, - n_uniform_longs * sizeof (unsigned long)); - data.n_differences = G_MAXINT; - } - else if (program_state->last_used_for_pipeline) - { - int i; - - memset (data.uniform_differences, 0, - n_uniform_longs * sizeof (unsigned long)); - _cogl_pipeline_compare_uniform_differences - (data.uniform_differences, - program_state->last_used_for_pipeline, - pipeline); - - /* We need to be sure to flush any uniforms that have changed - since the last flush */ - if (uniforms_state) - _cogl_bitmask_set_flags (&uniforms_state->changed_mask, - data.uniform_differences); - - /* Count the number of differences. This is so we can stop early - when we've flushed all of them */ - data.n_differences = 0; - - for (i = 0; i < n_uniform_longs; i++) - data.n_differences += - _cogl_util_popcountl (data.uniform_differences[i]); - } - - while (pipeline && data.n_differences > 0) - { - if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS) - { - const CoglPipelineUniformsState *parent_uniforms_state = - &pipeline->big_state->uniforms_state; - - data.values = parent_uniforms_state->override_values; - data.value_index = 0; - - _cogl_bitmask_foreach (&parent_uniforms_state->override_mask, - flush_uniform_cb, - &data); - } - - pipeline = _cogl_pipeline_get_parent (pipeline); - } - - if (uniforms_state) - _cogl_bitmask_clear_all (&uniforms_state->changed_mask); -} - -static gboolean -_cogl_pipeline_progend_glsl_start (CoglPipeline *pipeline) -{ - return TRUE; -} - -static void -_cogl_shader_compile_real (CoglHandle handle, - CoglPipeline *pipeline) -{ - CoglShader *shader = handle; - GLenum gl_type; - GLint status; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (shader->gl_handle) - { - CoglPipeline *prev = shader->compilation_pipeline; - - /* XXX: currently the only things that will affect the - * boilerplate for user shaders, apart from driver features, - * are the pipeline layer-indices and texture-unit-indices - */ - if (pipeline == prev || - _cogl_pipeline_layer_and_unit_numbers_equal (prev, pipeline)) - return; - - GE (ctx, glDeleteShader (shader->gl_handle)); - shader->gl_handle = 0; - - if (shader->compilation_pipeline) - { - cogl_object_unref (shader->compilation_pipeline); - shader->compilation_pipeline = NULL; - } - } - - 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; - default: - g_assert_not_reached (); - break; - } - - shader->gl_handle = ctx->glCreateShader (gl_type); - - _cogl_glsl_shader_set_source_with_boilerplate (ctx, - shader->gl_handle, - gl_type, - pipeline, - 1, - (const char **) - &shader->source, - NULL); - GE (ctx, glCompileShader (shader->gl_handle)); - - shader->compilation_pipeline = cogl_object_ref (pipeline); - - GE (ctx, glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status)); - if (!status) - { - char buffer[512]; - int len = 0; - - ctx->glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer); - buffer[len] = '\0'; - - g_warning ("Failed to compile GLSL program:\n" - "src:\n%s\n" - "error:\n%s\n", - shader->source, - buffer); - } -} - -static void -_cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline, - unsigned long pipelines_difference) -{ - CoglPipelineProgramState *program_state; - GLuint gl_program; - gboolean program_changed = FALSE; - UpdateUniformsState state; - CoglProgram *user_program; - CoglPipelineCacheEntry *cache_entry = NULL; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - program_state = get_program_state (pipeline); - - user_program = cogl_pipeline_get_user_program (pipeline); - - if (program_state == NULL) - { - CoglPipeline *authority; - - /* Get the authority for anything affecting program state. This - should include both fragment codegen state and vertex codegen - state */ - authority = _cogl_pipeline_find_equivalent_parent - (pipeline, - (_cogl_pipeline_get_state_for_vertex_codegen (ctx) | - _cogl_pipeline_get_state_for_fragment_codegen (ctx)) & - ~COGL_PIPELINE_STATE_LAYERS, - _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) | - COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN); - - program_state = get_program_state (authority); - - if (program_state == NULL) - { - /* Check if there is already a similar cached pipeline whose - program state we can share */ - if (G_LIKELY (!(COGL_DEBUG_ENABLED - (COGL_DEBUG_DISABLE_PROGRAM_CACHES)))) - { - cache_entry = - _cogl_pipeline_cache_get_combined_template (ctx->pipeline_cache, - authority); - - program_state = get_program_state (cache_entry->pipeline); - } - - if (program_state) - program_state->ref_count++; - else - program_state - = program_state_new (cogl_pipeline_get_n_layers (authority), - cache_entry); - - set_program_state (authority, program_state); - - program_state->ref_count--; - - if (cache_entry) - set_program_state (cache_entry->pipeline, program_state); - } - - if (authority != pipeline) - set_program_state (pipeline, program_state); - } - - /* If the program has changed since the last link then we do - * need to relink */ - if (program_state->program && user_program && - user_program->age != program_state->user_program_age) - { - GE( ctx, glDeleteProgram (program_state->program) ); - program_state->program = 0; - } - - if (program_state->program == 0) - { - GLuint backend_shader; - GSList *l; - - GE_RET( program_state->program, ctx, glCreateProgram () ); - - /* Attach all of the shader from the user program */ - if (user_program) - { - for (l = user_program->attached_shaders; l; l = l->next) - { - CoglShader *shader = l->data; - - _cogl_shader_compile_real (shader, pipeline); - - GE( ctx, glAttachShader (program_state->program, - shader->gl_handle) ); - } - - program_state->user_program_age = user_program->age; - } - - /* Attach any shaders from the GLSL backends */ - if ((backend_shader = _cogl_pipeline_fragend_glsl_get_shader (pipeline))) - GE( ctx, glAttachShader (program_state->program, backend_shader) ); - if ((backend_shader = _cogl_pipeline_vertend_glsl_get_shader (pipeline))) - GE( ctx, glAttachShader (program_state->program, backend_shader) ); - - /* XXX: OpenGL as a special case requires the vertex position to - * be bound to generic attribute 0 so for simplicity we - * unconditionally bind the cogl_position_in attribute here... - */ - GE( ctx, glBindAttribLocation (program_state->program, - 0, "cogl_position_in")); - - link_program (program_state->program); - - program_changed = TRUE; - } - - gl_program = program_state->program; - - if (ctx->current_gl_program != gl_program) - { - _cogl_gl_util_clear_gl_errors (ctx); - ctx->glUseProgram (gl_program); - if (_cogl_gl_util_get_error (ctx) == GL_NO_ERROR) - ctx->current_gl_program = gl_program; - else - { - GE( ctx, glUseProgram (0) ); - ctx->current_gl_program = 0; - } - } - - state.unit = 0; - state.gl_program = gl_program; - state.program_state = program_state; - - if (program_changed) - { - cogl_pipeline_foreach_layer (pipeline, - get_uniform_cb, - &state); - clear_attribute_cache (program_state); - - GE_RET (program_state->flip_uniform, - ctx, glGetUniformLocation (gl_program, "_cogl_flip_vector")); - program_state->flushed_flip_state = -1; - } - - state.unit = 0; - state.update_all = (program_changed || - program_state->last_used_for_pipeline != pipeline); - - cogl_pipeline_foreach_layer (pipeline, - update_constants_cb, - &state); - - if (program_changed) - { - int i; - - clear_flushed_matrix_stacks (program_state); - - for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++) - GE_RET( program_state->builtin_uniform_locations[i], ctx, - glGetUniformLocation (gl_program, - builtin_uniforms[i].uniform_name) ); - - GE_RET( program_state->modelview_uniform, ctx, - glGetUniformLocation (gl_program, - "cogl_modelview_matrix") ); - - GE_RET( program_state->projection_uniform, ctx, - glGetUniformLocation (gl_program, - "cogl_projection_matrix") ); - - GE_RET( program_state->mvp_uniform, ctx, - glGetUniformLocation (gl_program, - "cogl_modelview_projection_matrix") ); - } - - if (program_changed || - program_state->last_used_for_pipeline != pipeline) - program_state->dirty_builtin_uniforms = ~(unsigned long) 0; - - update_builtin_uniforms (ctx, pipeline, gl_program, program_state); - - _cogl_pipeline_progend_glsl_flush_uniforms (pipeline, - program_state, - gl_program, - program_changed); - - if (user_program) - _cogl_program_flush_uniforms (user_program, - gl_program, - program_changed); - - /* We need to track the last pipeline that the program was used with - * so know if we need to update all of the uniforms */ - program_state->last_used_for_pipeline = pipeline; -} - -static void -_cogl_pipeline_progend_glsl_pre_change_notify (CoglPipeline *pipeline, - CoglPipelineState change, - const CoglColor *new_color) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if ((change & (_cogl_pipeline_get_state_for_vertex_codegen (ctx) | - _cogl_pipeline_get_state_for_fragment_codegen (ctx)))) - { - dirty_program_state (pipeline); - } - else - { - int i; - - for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++) - if (change & builtin_uniforms[i].change) - { - CoglPipelineProgramState *program_state - = get_program_state (pipeline); - if (program_state) - program_state->dirty_builtin_uniforms |= 1 << i; - return; - } - } -} - -/* NB: layers are considered immutable once they have any dependants - * so although multiple pipelines can end up depending on a single - * static layer, we can guarantee that if a layer is being *changed* - * then it can only have one pipeline depending on it. - * - * XXX: Don't forget this is *pre* change, we can't read the new value - * yet! - */ -static void -_cogl_pipeline_progend_glsl_layer_pre_change_notify ( - CoglPipeline *owner, - CoglPipelineLayer *layer, - CoglPipelineLayerState change) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - CoglTextureUnit *unit; - - if ((change & (_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) | - COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN))) - { - dirty_program_state (owner); - } - else if (change & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT) - { - CoglPipelineProgramState *program_state = get_program_state (owner); - if (program_state) - { - int unit_index = _cogl_pipeline_layer_get_unit_index (layer); - program_state->unit_state[unit_index].dirty_combine_constant = TRUE; - } - } - else if (change & COGL_PIPELINE_LAYER_STATE_USER_MATRIX) - { - CoglPipelineProgramState *program_state = get_program_state (owner); - if (program_state) - { - int unit_index = _cogl_pipeline_layer_get_unit_index (layer); - program_state->unit_state[unit_index].dirty_texture_matrix = TRUE; - } - } - - /* If the layer being changed is the same as the last layer we - * flushed to the corresponding texture unit then we keep a track of - * the changes so we can try to minimize redundant OpenGL calls if - * the same layer is flushed again. - */ - unit = _cogl_get_texture_unit (_cogl_pipeline_layer_get_unit_index (layer)); - if (unit->layer == layer) - unit->layer_changes_since_flush |= change; -} - -static void -_cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline, - CoglFramebuffer *framebuffer) -{ - gboolean needs_flip; - CoglMatrixEntry *projection_entry; - CoglMatrixEntry *modelview_entry; - CoglPipelineProgramState *program_state; - gboolean modelview_changed; - gboolean projection_changed; - gboolean need_modelview; - gboolean need_projection; - graphene_matrix_t modelview, projection; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - program_state = get_program_state (pipeline); - - projection_entry = ctx->current_projection_entry; - modelview_entry = ctx->current_modelview_entry; - - /* An initial pipeline is flushed while creating the context. At - this point there are no matrices selected so we can't do - anything */ - if (modelview_entry == NULL || projection_entry == NULL) - return; - - needs_flip = cogl_framebuffer_is_y_flipped (ctx->current_draw_buffer); - - projection_changed = - _cogl_matrix_entry_cache_maybe_update (&program_state->projection_cache, - projection_entry, - (needs_flip && - program_state->flip_uniform == - -1)); - - modelview_changed = - _cogl_matrix_entry_cache_maybe_update (&program_state->modelview_cache, - modelview_entry, - /* never flip modelview */ - FALSE); - - if (modelview_changed || projection_changed) - { - float v[16]; - - if (program_state->mvp_uniform != -1) - need_modelview = need_projection = TRUE; - else - { - need_projection = (program_state->projection_uniform != -1 && - projection_changed); - need_modelview = (program_state->modelview_uniform != -1 && - modelview_changed); - } - - if (need_modelview) - cogl_matrix_entry_get (modelview_entry, &modelview); - if (need_projection) - { - if (needs_flip && program_state->flip_uniform == -1) - { - graphene_matrix_t tmp_matrix; - cogl_matrix_entry_get (projection_entry, &tmp_matrix); - graphene_matrix_multiply (&tmp_matrix, - &ctx->y_flip_matrix, - &projection); - } - else - cogl_matrix_entry_get (projection_entry, &projection); - } - - if (projection_changed && program_state->projection_uniform != -1) - { - graphene_matrix_to_float (&projection, v); - GE (ctx, glUniformMatrix4fv (program_state->projection_uniform, - 1, /* count */ - FALSE, /* transpose */ - v)); - } - - if (modelview_changed && program_state->modelview_uniform != -1) - { - graphene_matrix_to_float (&modelview,v); - GE (ctx, glUniformMatrix4fv (program_state->modelview_uniform, - 1, /* count */ - FALSE, /* transpose */ - v)); - } - - if (program_state->mvp_uniform != -1) - { - /* The journal usually uses an identity matrix for the - modelview so we can optimise this common case by - avoiding the matrix multiplication */ - if (cogl_matrix_entry_is_identity (modelview_entry)) - { - graphene_matrix_to_float (&projection, v); - GE (ctx, - glUniformMatrix4fv (program_state->mvp_uniform, - 1, /* count */ - FALSE, /* transpose */ - v)); - } - else - { - graphene_matrix_t combined; - - graphene_matrix_multiply (&modelview, &projection, &combined); - graphene_matrix_to_float (&combined, v); - - GE (ctx, - glUniformMatrix4fv (program_state->mvp_uniform, - 1, /* count */ - FALSE, /* transpose */ - v)); - } - } - } - - if (program_state->flip_uniform != -1 - && program_state->flushed_flip_state != needs_flip) - { - static const float do_flip[4] = { 1.0f, -1.0f, 1.0f, 1.0f }; - static const float dont_flip[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - GE( ctx, glUniform4fv (program_state->flip_uniform, - 1, /* count */ - needs_flip ? do_flip : dont_flip) ); - program_state->flushed_flip_state = needs_flip; - } -} - -static void -update_float_uniform (CoglPipeline *pipeline, - int uniform_location, - void *getter_func) -{ - float (* float_getter_func) (CoglPipeline *) = getter_func; - float value; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - value = float_getter_func (pipeline); - GE( ctx, glUniform1f (uniform_location, value) ); -} - -const CoglPipelineProgend _cogl_pipeline_glsl_progend = - { - _cogl_pipeline_progend_glsl_start, - _cogl_pipeline_progend_glsl_end, - _cogl_pipeline_progend_glsl_pre_change_notify, - _cogl_pipeline_progend_glsl_layer_pre_change_notify, - _cogl_pipeline_progend_glsl_pre_paint - }; diff --git a/cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl-private.h b/cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl-private.h deleted file mode 100644 index 4bd3823d0..000000000 --- a/cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl-private.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2010 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Robert Bragg <robert@linux.intel.com> - */ - -#ifndef __COGL_PIPELINE_VERTEND_GLSL_PRIVATE_H -#define __COGL_PIPELINE_VERTEND_GLSL_PRIVATE_H - -#include "cogl-pipeline-private.h" - -extern const CoglPipelineVertend _cogl_pipeline_glsl_vertend; - -GLuint -_cogl_pipeline_vertend_glsl_get_shader (CoglPipeline *pipeline); - -#endif /* __COGL_PIPELINE_VERTEND_GLSL_PRIVATE_H */ - diff --git a/cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl.c b/cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl.c deleted file mode 100644 index 28b5d5d76..000000000 --- a/cogl/cogl/driver/gl/cogl-pipeline-vertend-glsl.c +++ /dev/null @@ -1,794 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2010,2013 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Neil Roberts <neil@linux.intel.com> - */ - -#include "cogl-config.h" - -#include <string.h> - -#include <test-fixtures/test-unit.h> - -#include "cogl-context-private.h" -#include "cogl-pipeline-private.h" -#include "driver/gl/cogl-util-gl-private.h" -#include "driver/gl/cogl-pipeline-opengl-private.h" - -#include "cogl-context-private.h" -#include "cogl-object-private.h" -#include "cogl-pipeline-state-private.h" -#include "cogl-glsl-shader-boilerplate.h" -#include "driver/gl/cogl-pipeline-vertend-glsl-private.h" -#include "deprecated/cogl-program-private.h" - -const CoglPipelineVertend _cogl_pipeline_glsl_vertend; - -typedef struct -{ - unsigned int ref_count; - - GLuint gl_shader; - GString *header, *source; - - CoglPipelineCacheEntry *cache_entry; -} CoglPipelineShaderState; - -static CoglUserDataKey shader_state_key; - -static CoglPipelineShaderState * -shader_state_new (CoglPipelineCacheEntry *cache_entry) -{ - CoglPipelineShaderState *shader_state; - - shader_state = g_new0 (CoglPipelineShaderState, 1); - shader_state->ref_count = 1; - shader_state->cache_entry = cache_entry; - - return shader_state; -} - -static CoglPipelineShaderState * -get_shader_state (CoglPipeline *pipeline) -{ - return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key); -} - -static void -destroy_shader_state (void *user_data, - void *instance) -{ - CoglPipelineShaderState *shader_state = user_data; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if (shader_state->cache_entry && - shader_state->cache_entry->pipeline != instance) - shader_state->cache_entry->usage_count--; - - if (--shader_state->ref_count == 0) - { - if (shader_state->gl_shader) - GE( ctx, glDeleteShader (shader_state->gl_shader) ); - - g_free (shader_state); - } -} - -static void -set_shader_state (CoglPipeline *pipeline, - CoglPipelineShaderState *shader_state) -{ - if (shader_state) - { - shader_state->ref_count++; - - /* If we're not setting the state on the template pipeline then - * mark it as a usage of the pipeline cache entry */ - if (shader_state->cache_entry && - shader_state->cache_entry->pipeline != pipeline) - shader_state->cache_entry->usage_count++; - } - - _cogl_object_set_user_data (COGL_OBJECT (pipeline), - &shader_state_key, - shader_state, - destroy_shader_state); -} - -static void -dirty_shader_state (CoglPipeline *pipeline) -{ - cogl_object_set_user_data (COGL_OBJECT (pipeline), - &shader_state_key, - NULL, - NULL); -} - -static gboolean -add_layer_vertex_boilerplate_cb (CoglPipelineLayer *layer, - void *user_data) -{ - GString *layer_declarations = user_data; - int unit_index = _cogl_pipeline_layer_get_unit_index (layer); - g_string_append_printf (layer_declarations, - "attribute vec4 cogl_tex_coord%d_in;\n" - "#define cogl_texture_matrix%i cogl_texture_matrix[%i]\n" - "#define cogl_tex_coord%i_out _cogl_tex_coord[%i]\n", - layer->index, - layer->index, - unit_index, - layer->index, - unit_index); - return TRUE; -} - -static gboolean -add_layer_fragment_boilerplate_cb (CoglPipelineLayer *layer, - void *user_data) -{ - GString *layer_declarations = user_data; - g_string_append_printf (layer_declarations, - "#define cogl_tex_coord%i_in _cogl_tex_coord[%i]\n", - layer->index, - _cogl_pipeline_layer_get_unit_index (layer)); - return TRUE; -} - -void -_cogl_glsl_shader_set_source_with_boilerplate (CoglContext *ctx, - GLuint shader_gl_handle, - GLenum shader_gl_type, - CoglPipeline *pipeline, - GLsizei count_in, - const char **strings_in, - const GLint *lengths_in) -{ - const char *vertex_boilerplate; - const char *fragment_boilerplate; - - const char **strings = g_alloca (sizeof (char *) * (count_in + 4)); - GLint *lengths = g_alloca (sizeof (GLint) * (count_in + 4)); - char *version_string; - int count = 0; - - int n_layers; - - vertex_boilerplate = _COGL_VERTEX_SHADER_BOILERPLATE; - fragment_boilerplate = _COGL_FRAGMENT_SHADER_BOILERPLATE; - - version_string = g_strdup_printf ("#version %i\n\n", - ctx->glsl_version_to_use); - strings[count] = version_string; - lengths[count++] = -1; - - if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL)) - { - static const char image_external_extension[] = - "#extension GL_OES_EGL_image_external : require\n"; - strings[count] = image_external_extension; - lengths[count++] = sizeof (image_external_extension) - 1; - } - - if (shader_gl_type == GL_VERTEX_SHADER) - { - strings[count] = vertex_boilerplate; - lengths[count++] = strlen (vertex_boilerplate); - } - else if (shader_gl_type == GL_FRAGMENT_SHADER) - { - strings[count] = fragment_boilerplate; - lengths[count++] = strlen (fragment_boilerplate); - } - - n_layers = cogl_pipeline_get_n_layers (pipeline); - if (n_layers) - { - GString *layer_declarations = ctx->codegen_boilerplate_buffer; - g_string_set_size (layer_declarations, 0); - - g_string_append_printf (layer_declarations, - "varying vec4 _cogl_tex_coord[%d];\n", - n_layers); - - if (shader_gl_type == GL_VERTEX_SHADER) - { - g_string_append_printf (layer_declarations, - "uniform mat4 cogl_texture_matrix[%d];\n", - n_layers); - - _cogl_pipeline_foreach_layer_internal (pipeline, - add_layer_vertex_boilerplate_cb, - layer_declarations); - } - else if (shader_gl_type == GL_FRAGMENT_SHADER) - { - _cogl_pipeline_foreach_layer_internal (pipeline, - add_layer_fragment_boilerplate_cb, - layer_declarations); - } - - strings[count] = layer_declarations->str; - lengths[count++] = -1; /* null terminated */ - } - - memcpy (strings + count, strings_in, sizeof (char *) * count_in); - if (lengths_in) - memcpy (lengths + count, lengths_in, sizeof (GLint) * count_in); - else - { - int i; - - for (i = 0; i < count_in; i++) - lengths[count + i] = -1; /* null terminated */ - } - count += count_in; - - if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE))) - { - GString *buf = g_string_new (NULL); - int i; - - g_string_append_printf (buf, - "%s shader:\n", - shader_gl_type == GL_VERTEX_SHADER ? - "vertex" : "fragment"); - for (i = 0; i < count; i++) - if (lengths[i] != -1) - g_string_append_len (buf, strings[i], lengths[i]); - else - g_string_append (buf, strings[i]); - - g_message ("%s", buf->str); - - g_string_free (buf, TRUE); - } - - GE( ctx, glShaderSource (shader_gl_handle, count, - (const char **) strings, lengths) ); - - g_free (version_string); -} -GLuint -_cogl_pipeline_vertend_glsl_get_shader (CoglPipeline *pipeline) -{ - CoglPipelineShaderState *shader_state = get_shader_state (pipeline); - - if (shader_state) - return shader_state->gl_shader; - else - return 0; -} - -static CoglPipelineSnippetList * -get_vertex_snippets (CoglPipeline *pipeline) -{ - pipeline = - _cogl_pipeline_get_authority (pipeline, - COGL_PIPELINE_STATE_VERTEX_SNIPPETS); - - return &pipeline->big_state->vertex_snippets; -} - -static CoglPipelineSnippetList * -get_layer_vertex_snippets (CoglPipelineLayer *layer) -{ - unsigned long state = COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS; - layer = _cogl_pipeline_layer_get_authority (layer, state); - - return &layer->big_state->vertex_snippets; -} - -static gboolean -add_layer_declaration_cb (CoglPipelineLayer *layer, - void *user_data) -{ - CoglPipelineShaderState *shader_state = user_data; - - g_string_append_printf (shader_state->header, - "uniform sampler2D cogl_sampler%i;\n", - layer->index); - - return TRUE; -} - -static void -add_layer_declarations (CoglPipeline *pipeline, - CoglPipelineShaderState *shader_state) -{ - /* We always emit sampler uniforms in case there will be custom - * layer snippets that want to sample arbitrary layers. */ - - _cogl_pipeline_foreach_layer_internal (pipeline, - add_layer_declaration_cb, - shader_state); -} - -static void -add_global_declarations (CoglPipeline *pipeline, - CoglPipelineShaderState *shader_state) -{ - CoglSnippetHook hook = COGL_SNIPPET_HOOK_VERTEX_GLOBALS; - CoglPipelineSnippetList *snippets = get_vertex_snippets (pipeline); - - /* Add the global data hooks. All of the code in these snippets is - * always added and only the declarations data is used */ - - _cogl_pipeline_snippet_generate_declarations (shader_state->header, - hook, - snippets); -} - -static void -_cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline, - int n_layers, - unsigned long pipelines_difference) -{ - CoglPipelineShaderState *shader_state; - CoglPipelineCacheEntry *cache_entry = NULL; - CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline); - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* Now lookup our glsl backend private state (allocating if - * necessary) */ - shader_state = get_shader_state (pipeline); - - if (shader_state == NULL) - { - CoglPipeline *authority; - - /* Get the authority for anything affecting vertex shader - state */ - authority = _cogl_pipeline_find_equivalent_parent - (pipeline, - _cogl_pipeline_get_state_for_vertex_codegen (ctx) & - ~COGL_PIPELINE_STATE_LAYERS, - COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN); - - shader_state = get_shader_state (authority); - - if (shader_state == NULL) - { - /* Check if there is already a similar cached pipeline whose - shader state we can share */ - if (G_LIKELY (!(COGL_DEBUG_ENABLED - (COGL_DEBUG_DISABLE_PROGRAM_CACHES)))) - { - cache_entry = - _cogl_pipeline_cache_get_vertex_template (ctx->pipeline_cache, - authority); - - shader_state = get_shader_state (cache_entry->pipeline); - } - - if (shader_state) - shader_state->ref_count++; - else - shader_state = shader_state_new (cache_entry); - - set_shader_state (authority, shader_state); - - shader_state->ref_count--; - - if (cache_entry) - set_shader_state (cache_entry->pipeline, shader_state); - } - - if (authority != pipeline) - set_shader_state (pipeline, shader_state); - } - - if (user_program) - { - /* If the user program contains a vertex shader then we don't need - to generate one */ - if (_cogl_program_has_vertex_shader (user_program)) - { - if (shader_state->gl_shader) - { - GE( ctx, glDeleteShader (shader_state->gl_shader) ); - shader_state->gl_shader = 0; - } - return; - } - } - - if (shader_state->gl_shader) - return; - - /* If we make it here then we have a shader_state struct without a gl_shader - either because this is the first time we've encountered it or - because the user program has changed */ - - /* We reuse two grow-only GStrings for code-gen. One string - contains the uniform and attribute declarations while the - other contains the main function. We need two strings - because we need to dynamically declare attributes as the - add_layer callback is invoked */ - g_string_set_size (ctx->codegen_header_buffer, 0); - g_string_set_size (ctx->codegen_source_buffer, 0); - shader_state->header = ctx->codegen_header_buffer; - shader_state->source = ctx->codegen_source_buffer; - - add_layer_declarations (pipeline, shader_state); - add_global_declarations (pipeline, shader_state); - - g_string_append (shader_state->source, - "void\n" - "cogl_generated_source ()\n" - "{\n"); - - if (cogl_pipeline_get_per_vertex_point_size (pipeline)) - g_string_append (shader_state->header, - "attribute float cogl_point_size_in;\n"); - else - { - /* There is no builtin uniform for the point size on GLES2 so we - need to copy it from the custom uniform in the vertex shader - if we're not using per-vertex point sizes, however we'll only - do this if the point-size is non-zero. Toggle the point size - between zero and non-zero causes a state change which - generates a new program */ - if (cogl_pipeline_get_point_size (pipeline) > 0.0f) - { - g_string_append (shader_state->header, - "uniform float cogl_point_size_in;\n"); - g_string_append (shader_state->source, - " cogl_point_size_out = cogl_point_size_in;\n"); - } - } -} - -static gboolean -_cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline, - CoglPipelineLayer *layer, - unsigned long layers_difference, - CoglFramebuffer *framebuffer) -{ - CoglPipelineShaderState *shader_state; - CoglPipelineSnippetData snippet_data; - int layer_index = layer->index; - - _COGL_GET_CONTEXT (ctx, FALSE); - - shader_state = get_shader_state (pipeline); - - if (shader_state->source == NULL) - return TRUE; - - /* Transform the texture coordinates by the layer's user matrix. - * - * FIXME: this should avoid doing the transform if there is no user - * matrix set. This might need a separate layer state flag for - * whether there is a user matrix - * - * FIXME: we could be more clever here and try to detect if the - * fragment program is going to use the texture coordinates and - * avoid setting them if not - */ - - g_string_append_printf (shader_state->header, - "vec4\n" - "cogl_real_transform_layer%i (mat4 matrix, " - "vec4 tex_coord)\n" - "{\n" - " return matrix * tex_coord;\n" - "}\n", - layer_index); - - /* Wrap the layer code in any snippets that have been hooked */ - memset (&snippet_data, 0, sizeof (snippet_data)); - snippet_data.snippets = get_layer_vertex_snippets (layer); - snippet_data.hook = COGL_SNIPPET_HOOK_TEXTURE_COORD_TRANSFORM; - snippet_data.chain_function = g_strdup_printf ("cogl_real_transform_layer%i", - layer_index); - snippet_data.final_name = g_strdup_printf ("cogl_transform_layer%i", - layer_index); - snippet_data.function_prefix = g_strdup_printf ("cogl_transform_layer%i", - layer_index); - snippet_data.return_type = "vec4"; - snippet_data.return_variable = "cogl_tex_coord"; - snippet_data.return_variable_is_argument = TRUE; - snippet_data.arguments = "cogl_matrix, cogl_tex_coord"; - snippet_data.argument_declarations = "mat4 cogl_matrix, vec4 cogl_tex_coord"; - snippet_data.source_buf = shader_state->header; - - _cogl_pipeline_snippet_generate_code (&snippet_data); - - g_free ((char *) snippet_data.chain_function); - g_free ((char *) snippet_data.final_name); - g_free ((char *) snippet_data.function_prefix); - - g_string_append_printf (shader_state->source, - " cogl_tex_coord%i_out = " - "cogl_transform_layer%i (cogl_texture_matrix%i,\n" - " " - " cogl_tex_coord%i_in);\n", - layer_index, - layer_index, - layer_index, - layer_index); - - return TRUE; -} - -static gboolean -_cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline, - unsigned long pipelines_difference) -{ - CoglPipelineShaderState *shader_state; - - _COGL_GET_CONTEXT (ctx, FALSE); - - shader_state = get_shader_state (pipeline); - - if (shader_state->source) - { - const char *source_strings[2]; - GLint lengths[2]; - GLint compile_status; - GLuint shader; - CoglPipelineSnippetData snippet_data; - CoglPipelineSnippetList *vertex_snippets; - gboolean has_per_vertex_point_size = - cogl_pipeline_get_per_vertex_point_size (pipeline); - - COGL_STATIC_COUNTER (vertend_glsl_compile_counter, - "glsl vertex compile counter", - "Increments each time a new GLSL " - "vertex shader is compiled", - 0 /* no application private data */); - COGL_COUNTER_INC (_cogl_uprof_context, vertend_glsl_compile_counter); - - g_string_append (shader_state->header, - "void\n" - "cogl_real_vertex_transform ()\n" - "{\n" - " cogl_position_out = " - "cogl_modelview_projection_matrix * " - "cogl_position_in;\n" - "}\n"); - - g_string_append (shader_state->source, - " cogl_vertex_transform ();\n"); - - if (has_per_vertex_point_size) - { - g_string_append (shader_state->header, - "void\n" - "cogl_real_point_size_calculation ()\n" - "{\n" - " cogl_point_size_out = cogl_point_size_in;\n" - "}\n"); - g_string_append (shader_state->source, - " cogl_point_size_calculation ();\n"); - } - - g_string_append (shader_state->source, - " cogl_color_out = cogl_color_in;\n" - "}\n"); - - vertex_snippets = get_vertex_snippets (pipeline); - - /* Add hooks for the vertex transform part */ - memset (&snippet_data, 0, sizeof (snippet_data)); - snippet_data.snippets = vertex_snippets; - snippet_data.hook = COGL_SNIPPET_HOOK_VERTEX_TRANSFORM; - snippet_data.chain_function = "cogl_real_vertex_transform"; - snippet_data.final_name = "cogl_vertex_transform"; - snippet_data.function_prefix = "cogl_vertex_transform"; - snippet_data.source_buf = shader_state->header; - _cogl_pipeline_snippet_generate_code (&snippet_data); - - /* Add hooks for the point size calculation part */ - if (has_per_vertex_point_size) - { - memset (&snippet_data, 0, sizeof (snippet_data)); - snippet_data.snippets = vertex_snippets; - snippet_data.hook = COGL_SNIPPET_HOOK_POINT_SIZE; - snippet_data.chain_function = "cogl_real_point_size_calculation"; - snippet_data.final_name = "cogl_point_size_calculation"; - snippet_data.function_prefix = "cogl_point_size_calculation"; - snippet_data.source_buf = shader_state->header; - _cogl_pipeline_snippet_generate_code (&snippet_data); - } - - /* Add all of the hooks for vertex processing */ - memset (&snippet_data, 0, sizeof (snippet_data)); - snippet_data.snippets = vertex_snippets; - snippet_data.hook = COGL_SNIPPET_HOOK_VERTEX; - snippet_data.chain_function = "cogl_generated_source"; - snippet_data.final_name = "cogl_vertex_hook"; - snippet_data.function_prefix = "cogl_vertex_hook"; - snippet_data.source_buf = shader_state->source; - _cogl_pipeline_snippet_generate_code (&snippet_data); - - g_string_append (shader_state->source, - "void\n" - "main ()\n" - "{\n" - " cogl_vertex_hook ();\n"); - - /* If there are any snippets then we can't rely on the - projection matrix to flip the rendering for offscreen buffers - so we'll need to flip it using an extra statement and a - uniform */ - if (_cogl_pipeline_has_vertex_snippets (pipeline)) - { - g_string_append (shader_state->header, - "uniform vec4 _cogl_flip_vector;\n"); - g_string_append (shader_state->source, - " cogl_position_out *= _cogl_flip_vector;\n"); - } - - g_string_append (shader_state->source, - "}\n"); - - GE_RET( shader, ctx, glCreateShader (GL_VERTEX_SHADER) ); - - lengths[0] = shader_state->header->len; - source_strings[0] = shader_state->header->str; - lengths[1] = shader_state->source->len; - source_strings[1] = shader_state->source->str; - - _cogl_glsl_shader_set_source_with_boilerplate (ctx, - shader, GL_VERTEX_SHADER, - pipeline, - 2, /* count */ - source_strings, lengths); - - GE( ctx, glCompileShader (shader) ); - GE( ctx, glGetShaderiv (shader, GL_COMPILE_STATUS, &compile_status) ); - - if (!compile_status) - { - GLint len = 0; - char *shader_log; - - GE( ctx, glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &len) ); - shader_log = g_alloca (len); - GE( ctx, glGetShaderInfoLog (shader, len, &len, shader_log) ); - g_warning ("Shader compilation failed:\n%s", shader_log); - } - - shader_state->header = NULL; - shader_state->source = NULL; - shader_state->gl_shader = shader; - } - - return TRUE; -} - -static void -_cogl_pipeline_vertend_glsl_pre_change_notify (CoglPipeline *pipeline, - CoglPipelineState change, - const CoglColor *new_color) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - if ((change & _cogl_pipeline_get_state_for_vertex_codegen (ctx))) - dirty_shader_state (pipeline); -} - -/* NB: layers are considered immutable once they have any dependants - * so although multiple pipelines can end up depending on a single - * static layer, we can guarantee that if a layer is being *changed* - * then it can only have one pipeline depending on it. - * - * XXX: Don't forget this is *pre* change, we can't read the new value - * yet! - */ -static void -_cogl_pipeline_vertend_glsl_layer_pre_change_notify ( - CoglPipeline *owner, - CoglPipelineLayer *layer, - CoglPipelineLayerState change) -{ - CoglPipelineShaderState *shader_state; - - shader_state = get_shader_state (owner); - if (!shader_state) - return; - - if ((change & COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN)) - { - dirty_shader_state (owner); - return; - } - - /* TODO: we could be saving snippets of texture combine code along - * with each layer and then when a layer changes we would just free - * the snippet. */ -} - -const CoglPipelineVertend _cogl_pipeline_glsl_vertend = - { - _cogl_pipeline_vertend_glsl_start, - _cogl_pipeline_vertend_glsl_add_layer, - _cogl_pipeline_vertend_glsl_end, - _cogl_pipeline_vertend_glsl_pre_change_notify, - _cogl_pipeline_vertend_glsl_layer_pre_change_notify - }; - -UNIT_TEST (check_point_size_shader, - 0 /* no requirements */, - 0 /* no failure cases */) -{ - CoglPipeline *pipelines[4]; - CoglPipelineShaderState *shader_states[G_N_ELEMENTS (pipelines)]; - int i; - - /* Default pipeline with zero point size */ - pipelines[0] = cogl_pipeline_new (test_ctx); - - /* Point size 1 */ - pipelines[1] = cogl_pipeline_new (test_ctx); - cogl_pipeline_set_point_size (pipelines[1], 1.0f); - - /* Point size 2 */ - pipelines[2] = cogl_pipeline_new (test_ctx); - cogl_pipeline_set_point_size (pipelines[2], 2.0f); - - /* Same as the first pipeline, but reached by restoring the old - * state from a copy */ - pipelines[3] = cogl_pipeline_copy (pipelines[1]); - cogl_pipeline_set_point_size (pipelines[3], 0.0f); - - /* Draw something with all of the pipelines to make sure their state - * is flushed */ - for (i = 0; i < G_N_ELEMENTS (pipelines); i++) - cogl_framebuffer_draw_rectangle (test_fb, - pipelines[i], - 0.0f, 0.0f, - 10.0f, 10.0f); - cogl_framebuffer_finish (test_fb); - - /* Get all of the shader states. These might be NULL if the driver - * is not using GLSL */ - for (i = 0; i < G_N_ELEMENTS (pipelines); i++) - shader_states[i] = get_shader_state (pipelines[i]); - - /* If the first two pipelines are using GLSL then they should have - * the same shader unless there is no builtin uniform for the point - * size */ - if (shader_states[0]) - { - g_assert (shader_states[0] != shader_states[1]); - } - - /* The second and third pipelines should always have the same shader - * state because only toggling between zero and non-zero should - * change the shader */ - g_assert (shader_states[1] == shader_states[2]); - - /* The fourth pipeline should be exactly the same as the first */ - g_assert (shader_states[0] == shader_states[3]); -} diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h b/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h deleted file mode 100644 index c10637627..000000000 --- a/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2012 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Robert Bragg <robert@linux.intel.com> - */ - -#ifndef _COGL_TEXTURE_2D_GL_PRIVATE_H_ -#define _COGL_TEXTURE_2D_GL_PRIVATE_H_ - -#include "cogl-types.h" -#include "cogl-context-private.h" -#include "cogl-texture.h" - -void -_cogl_texture_2d_gl_free (CoglTexture2D *tex_2d); - -gboolean -_cogl_texture_2d_gl_can_create (CoglContext *ctx, - int width, - int height, - CoglPixelFormat internal_format); - -void -_cogl_texture_2d_gl_init (CoglTexture2D *tex_2d); - -gboolean -_cogl_texture_2d_gl_allocate (CoglTexture *tex, - GError **error); - -CoglTexture2D * -_cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp, - CoglPixelFormat internal_format, - gboolean can_convert_in_place, - GError **error); - -#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) -CoglTexture2D * -_cogl_egl_texture_2d_gl_new_from_image (CoglContext *ctx, - int width, - int height, - CoglPixelFormat format, - EGLImageKHR image, - GError **error); -#endif - -void -_cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex, - GLenum min_filter, - GLenum mag_filter); - -void -_cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, - GLenum wrap_mode_s, - GLenum wrap_mode_t); - -void -_cogl_texture_2d_gl_copy_from_framebuffer (CoglTexture2D *tex_2d, - int src_x, - int src_y, - int width, - int height, - CoglFramebuffer *src_fb, - int dst_x, - int dst_y, - int level); - -unsigned int -_cogl_texture_2d_gl_get_gl_handle (CoglTexture2D *tex_2d); - -void -_cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d); - -gboolean -_cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, - int src_x, - int src_y, - int width, - int height, - CoglBitmap *bitmap, - int dst_x, - int dst_y, - int level, - GError **error); - -gboolean -_cogl_texture_2d_gl_is_get_data_supported (CoglTexture2D *tex_2d); - -void -_cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d, - CoglPixelFormat format, - int rowstride, - uint8_t *data); - -#endif /* _COGL_TEXTURE_2D_GL_PRIVATE_H_ */ diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c deleted file mode 100644 index 4862dbe2e..000000000 --- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c +++ /dev/null @@ -1,632 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2009,2010,2011,2012 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Neil Roberts <neil@linux.intel.com> - * Robert Bragg <robert@linux.intel.com> - */ - -#include "cogl-config.h" - -#include <string.h> - -#include "cogl-private.h" -#include "cogl-texture-private.h" -#include "cogl-texture-2d-private.h" -#include "driver/gl/cogl-texture-2d-gl-private.h" -#include "driver/gl/cogl-texture-gl-private.h" -#include "driver/gl/cogl-pipeline-opengl-private.h" -#include "driver/gl/cogl-util-gl-private.h" - -#if defined (COGL_HAS_EGL_SUPPORT) - -/* We need this define from GLES2, but can't include the header - as its type definitions may conflict with the GL ones - */ -#ifndef GL_OES_EGL_image_external -#define GL_OES_EGL_image_external 1 -#define GL_TEXTURE_EXTERNAL_OES 0x8D65 -#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67 -#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68 -#define GL_SAMPLER_EXTERNAL_OES 0x8D66 -#endif /* GL_OES_EGL_image_external */ - -#endif /* defined (COGL_HAS_EGL_SUPPORT) */ - -void -_cogl_texture_2d_gl_free (CoglTexture2D *tex_2d) -{ - if (tex_2d->gl_texture) - _cogl_delete_gl_texture (tex_2d->gl_texture); - -#if defined (COGL_HAS_EGL_SUPPORT) - g_clear_pointer (&tex_2d->egl_image_external.user_data, - tex_2d->egl_image_external.destroy); -#endif -} - -gboolean -_cogl_texture_2d_gl_can_create (CoglContext *ctx, - int width, - int height, - CoglPixelFormat internal_format) -{ - GLenum gl_intformat; - GLenum gl_format; - GLenum gl_type; - - /* We only support single plane formats for now */ - if (cogl_pixel_format_get_n_planes (internal_format) != 1) - return FALSE; - - ctx->driver_vtable->pixel_format_to_gl (ctx, - internal_format, - &gl_intformat, - &gl_format, - &gl_type); - - /* Check that the driver can create a texture with that size */ - if (!ctx->texture_driver->size_supported (ctx, - GL_TEXTURE_2D, - gl_intformat, - gl_format, - gl_type, - width, - height)) - return FALSE; - - return TRUE; -} - -void -_cogl_texture_2d_gl_init (CoglTexture2D *tex_2d) -{ - tex_2d->gl_texture = 0; - - /* We default to GL_LINEAR for both filters */ - tex_2d->gl_legacy_texobj_min_filter = GL_LINEAR; - tex_2d->gl_legacy_texobj_mag_filter = GL_LINEAR; - - /* Wrap mode not yet set */ - tex_2d->gl_legacy_texobj_wrap_mode_s = GL_FALSE; - tex_2d->gl_legacy_texobj_wrap_mode_t = GL_FALSE; - - tex_2d->egl_image_external.user_data = NULL; - tex_2d->egl_image_external.destroy = NULL; -} - -static gboolean -allocate_with_size (CoglTexture2D *tex_2d, - CoglTextureLoader *loader, - GError **error) -{ - CoglTexture *tex = COGL_TEXTURE (tex_2d); - CoglPixelFormat internal_format; - int width = loader->src.sized.width; - int height = loader->src.sized.height; - CoglContext *ctx = tex->context; - GLenum gl_intformat; - GLenum gl_format; - GLenum gl_type; - GLenum gl_texture; - - internal_format = - _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY); - - if (!_cogl_texture_2d_gl_can_create (ctx, - width, - height, - internal_format)) - { - g_set_error_literal (error, COGL_TEXTURE_ERROR, - COGL_TEXTURE_ERROR_SIZE, - "Failed to create texture 2d due to size/format" - " constraints"); - return FALSE; - } - - ctx->driver_vtable->pixel_format_to_gl (ctx, - internal_format, - &gl_intformat, - &gl_format, - &gl_type); - - gl_texture = ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format); - - tex_2d->gl_internal_format = gl_intformat; - - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, - gl_texture); - - /* Clear any GL errors */ - _cogl_gl_util_clear_gl_errors (ctx); - - ctx->glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat, - width, height, 0, gl_format, gl_type, NULL); - - if (_cogl_gl_util_catch_out_of_memory (ctx, error)) - { - GE( ctx, glDeleteTextures (1, &gl_texture) ); - return FALSE; - } - - tex_2d->gl_texture = gl_texture; - tex_2d->gl_internal_format = gl_intformat; - - tex_2d->internal_format = internal_format; - - _cogl_texture_set_allocated (tex, internal_format, width, height); - - return TRUE; -} - -static gboolean -allocate_from_bitmap (CoglTexture2D *tex_2d, - CoglTextureLoader *loader, - GError **error) -{ - CoglTexture *tex = COGL_TEXTURE (tex_2d); - CoglBitmap *bmp = loader->src.bitmap.bitmap; - CoglContext *ctx = _cogl_bitmap_get_context (bmp); - CoglPixelFormat internal_format; - int width = cogl_bitmap_get_width (bmp); - int height = cogl_bitmap_get_height (bmp); - gboolean can_convert_in_place = loader->src.bitmap.can_convert_in_place; - CoglBitmap *upload_bmp; - GLenum gl_intformat; - GLenum gl_format; - GLenum gl_type; - - internal_format = - _cogl_texture_determine_internal_format (tex, cogl_bitmap_get_format (bmp)); - - if (!_cogl_texture_2d_gl_can_create (ctx, - width, - height, - internal_format)) - { - g_set_error_literal (error, COGL_TEXTURE_ERROR, - COGL_TEXTURE_ERROR_SIZE, - "Failed to create texture 2d due to size/format" - " constraints"); - return FALSE; - } - - upload_bmp = _cogl_bitmap_convert_for_upload (bmp, - internal_format, - can_convert_in_place, - error); - if (upload_bmp == NULL) - return FALSE; - - ctx->driver_vtable->pixel_format_to_gl (ctx, - cogl_bitmap_get_format (upload_bmp), - NULL, /* internal format */ - &gl_format, - &gl_type); - ctx->driver_vtable->pixel_format_to_gl (ctx, - internal_format, - &gl_intformat, - NULL, - NULL); - - tex_2d->gl_texture = - ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format); - if (!ctx->texture_driver->upload_to_gl (ctx, - GL_TEXTURE_2D, - tex_2d->gl_texture, - upload_bmp, - gl_intformat, - gl_format, - gl_type, - error)) - { - cogl_object_unref (upload_bmp); - return FALSE; - } - - tex_2d->gl_internal_format = gl_intformat; - - cogl_object_unref (upload_bmp); - - tex_2d->internal_format = internal_format; - - _cogl_texture_set_allocated (tex, internal_format, width, height); - - return TRUE; -} - -#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) -static gboolean -allocate_from_egl_image (CoglTexture2D *tex_2d, - CoglTextureLoader *loader, - GError **error) -{ - CoglTexture *tex = COGL_TEXTURE (tex_2d); - CoglContext *ctx = tex->context; - CoglPixelFormat internal_format = loader->src.egl_image.format; - - tex_2d->gl_texture = - ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format); - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, - tex_2d->gl_texture); - _cogl_gl_util_clear_gl_errors (ctx); - - ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, loader->src.egl_image.image); - if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR) - { - g_set_error_literal (error, - COGL_TEXTURE_ERROR, - COGL_TEXTURE_ERROR_BAD_PARAMETER, - "Could not create a CoglTexture2D from a given " - "EGLImage"); - GE( ctx, glDeleteTextures (1, &tex_2d->gl_texture) ); - return FALSE; - } - - tex_2d->internal_format = internal_format; - tex_2d->is_get_data_supported = - !(loader->src.egl_image.flags & COGL_EGL_IMAGE_FLAG_NO_GET_DATA); - - _cogl_texture_set_allocated (tex, - internal_format, - loader->src.egl_image.width, - loader->src.egl_image.height); - - return TRUE; -} -#endif - -#if defined (COGL_HAS_EGL_SUPPORT) -static gboolean -allocate_custom_egl_image_external (CoglTexture2D *tex_2d, - CoglTextureLoader *loader, - GError **error) -{ - CoglTexture *tex = COGL_TEXTURE (tex_2d); - CoglContext *ctx = tex->context; - CoglPixelFormat external_format; - CoglPixelFormat internal_format; - - external_format = loader->src.egl_image_external.format; - internal_format = _cogl_texture_determine_internal_format (tex, - external_format); - - _cogl_gl_util_clear_gl_errors (ctx); - - GE (ctx, glActiveTexture (GL_TEXTURE0)); - GE (ctx, glGenTextures (1, &tex_2d->gl_texture)); - - GE (ctx, glBindTexture (GL_TEXTURE_EXTERNAL_OES, - tex_2d->gl_texture)); - - if (_cogl_gl_util_get_error (ctx) != GL_NO_ERROR) - { - g_set_error_literal (error, - COGL_TEXTURE_ERROR, - COGL_TEXTURE_ERROR_BAD_PARAMETER, - "Could not create a CoglTexture2D from a given " - "EGLImage"); - GE( ctx, glDeleteTextures (1, &tex_2d->gl_texture) ); - return FALSE; - } - - GE (ctx, glTexParameteri(GL_TEXTURE_EXTERNAL_OES, - GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GE (ctx, glTexParameteri(GL_TEXTURE_EXTERNAL_OES, - GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - - if (!loader->src.egl_image_external.alloc (tex_2d, - tex_2d->egl_image_external.user_data, - error)) - { - GE (ctx, glBindTexture (GL_TEXTURE_EXTERNAL_OES, 0)); - GE (ctx, glDeleteTextures (1, &tex_2d->gl_texture)); - return FALSE; - } - - GE (ctx, glBindTexture (GL_TEXTURE_EXTERNAL_OES, 0)); - - tex_2d->internal_format = internal_format; - tex_2d->gl_target = GL_TEXTURE_EXTERNAL_OES; - tex_2d->is_get_data_supported = FALSE; - - return TRUE; -} - -CoglTexture2D * -cogl_texture_2d_new_from_egl_image_external (CoglContext *ctx, - int width, - int height, - CoglTexture2DEGLImageExternalAlloc alloc, - gpointer user_data, - GDestroyNotify destroy, - GError **error) -{ - CoglTextureLoader *loader; - CoglTexture2D *tex_2d; - CoglPixelFormat internal_format = COGL_PIXEL_FORMAT_ANY; - - g_return_val_if_fail (_cogl_context_get_winsys (ctx)->constraints & - COGL_RENDERER_CONSTRAINT_USES_EGL, - NULL); - - g_return_val_if_fail (cogl_has_feature (ctx, - COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL), - NULL); - - loader = _cogl_texture_create_loader (); - loader->src_type = COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE_EXTERNAL; - loader->src.egl_image_external.width = width; - loader->src.egl_image_external.height = height; - loader->src.egl_image_external.alloc = alloc; - loader->src.egl_image_external.format = internal_format; - - tex_2d = _cogl_texture_2d_create_base (ctx, width, height, - internal_format, loader); - - - tex_2d->egl_image_external.user_data = user_data; - tex_2d->egl_image_external.destroy = destroy; - - return tex_2d; -} -#endif /* defined (COGL_HAS_EGL_SUPPORT) */ - -gboolean -_cogl_texture_2d_gl_allocate (CoglTexture *tex, - GError **error) -{ - CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); - CoglTextureLoader *loader = tex->loader; - - g_return_val_if_fail (loader, FALSE); - - switch (loader->src_type) - { - case COGL_TEXTURE_SOURCE_TYPE_SIZED: - return allocate_with_size (tex_2d, loader, error); - case COGL_TEXTURE_SOURCE_TYPE_BITMAP: - return allocate_from_bitmap (tex_2d, loader, error); - case COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE: -#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) - return allocate_from_egl_image (tex_2d, loader, error); -#else - g_return_val_if_reached (FALSE); -#endif - case COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE_EXTERNAL: -#if defined (COGL_HAS_EGL_SUPPORT) - return allocate_custom_egl_image_external (tex_2d, loader, error); -#else - g_return_val_if_reached (FALSE); -#endif - } - - g_return_val_if_reached (FALSE); -} - -void -_cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex, - GLenum min_filter, - GLenum mag_filter) -{ - CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); - CoglContext *ctx = tex->context; - - if (min_filter == tex_2d->gl_legacy_texobj_min_filter - && mag_filter == tex_2d->gl_legacy_texobj_mag_filter) - return; - - /* Store new values */ - tex_2d->gl_legacy_texobj_min_filter = min_filter; - tex_2d->gl_legacy_texobj_mag_filter = mag_filter; - - /* Apply new filters to the texture */ - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, - tex_2d->gl_texture); - GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter) ); - GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter) ); -} - -void -_cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex, - GLenum wrap_mode_s, - GLenum wrap_mode_t) -{ - CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); - CoglContext *ctx = tex->context; - - /* Only set the wrap mode if it's different from the current value - to avoid too many GL calls. Texture 2D doesn't make use of the r - coordinate so we can ignore its wrap mode */ - if (tex_2d->gl_legacy_texobj_wrap_mode_s != wrap_mode_s || - tex_2d->gl_legacy_texobj_wrap_mode_t != wrap_mode_t) - { - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, - tex_2d->gl_texture); - GE( ctx, glTexParameteri (GL_TEXTURE_2D, - GL_TEXTURE_WRAP_S, - wrap_mode_s) ); - GE( ctx, glTexParameteri (GL_TEXTURE_2D, - GL_TEXTURE_WRAP_T, - wrap_mode_t) ); - - tex_2d->gl_legacy_texobj_wrap_mode_s = wrap_mode_s; - tex_2d->gl_legacy_texobj_wrap_mode_t = wrap_mode_t; - } -} - -void -_cogl_texture_2d_gl_copy_from_framebuffer (CoglTexture2D *tex_2d, - int src_x, - int src_y, - int width, - int height, - CoglFramebuffer *src_fb, - int dst_x, - int dst_y, - int level) -{ - CoglTexture *tex = COGL_TEXTURE (tex_2d); - CoglContext *ctx = tex->context; - - /* Make sure the current framebuffers are bound, though we don't need to - * flush the clip state here since we aren't going to draw to the - * framebuffer. */ - cogl_context_flush_framebuffer_state (ctx, - ctx->current_draw_buffer, - src_fb, - (COGL_FRAMEBUFFER_STATE_ALL & - ~COGL_FRAMEBUFFER_STATE_CLIP)); - - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, - tex_2d->gl_texture); - - ctx->glCopyTexSubImage2D (GL_TEXTURE_2D, - 0, /* level */ - dst_x, dst_y, - src_x, src_y, - width, height); -} - -unsigned int -_cogl_texture_2d_gl_get_gl_handle (CoglTexture2D *tex_2d) -{ - return tex_2d->gl_texture; -} - -void -_cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d) -{ - _cogl_texture_gl_generate_mipmaps (COGL_TEXTURE (tex_2d)); -} - -gboolean -_cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d, - int src_x, - int src_y, - int width, - int height, - CoglBitmap *bmp, - int dst_x, - int dst_y, - int level, - GError **error) -{ - CoglTexture *tex = COGL_TEXTURE (tex_2d); - CoglContext *ctx = tex->context; - CoglBitmap *upload_bmp; - CoglPixelFormat upload_format; - GLenum gl_format; - GLenum gl_type; - gboolean status = TRUE; - - upload_bmp = - _cogl_bitmap_convert_for_upload (bmp, - _cogl_texture_get_format (tex), - FALSE, /* can't convert in place */ - error); - if (upload_bmp == NULL) - return FALSE; - - upload_format = cogl_bitmap_get_format (upload_bmp); - - /* Only support single plane formats */ - if (upload_format == COGL_PIXEL_FORMAT_ANY || - cogl_pixel_format_get_n_planes (upload_format) != 1) - return FALSE; - - ctx->driver_vtable->pixel_format_to_gl (ctx, - upload_format, - NULL, /* internal gl format */ - &gl_format, - &gl_type); - - if (tex->max_level_set < level) - cogl_texture_gl_set_max_level (tex, level); - - status = ctx->texture_driver->upload_subregion_to_gl (ctx, - tex, - src_x, src_y, - dst_x, dst_y, - width, height, - level, - upload_bmp, - gl_format, - gl_type, - error); - - cogl_object_unref (upload_bmp); - - return status; -} - -gboolean -_cogl_texture_2d_gl_is_get_data_supported (CoglTexture2D *tex_2d) -{ - return tex_2d->is_get_data_supported; -} - -void -_cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d, - CoglPixelFormat format, - int rowstride, - uint8_t *data) -{ - CoglContext *ctx = COGL_TEXTURE (tex_2d)->context; - uint8_t bpp; - int width = COGL_TEXTURE (tex_2d)->width; - GLenum gl_format; - GLenum gl_type; - - g_return_if_fail (format != COGL_PIXEL_FORMAT_ANY); - g_return_if_fail (cogl_pixel_format_get_n_planes (format) == 1); - - bpp = cogl_pixel_format_get_bytes_per_pixel (format, 0); - - ctx->driver_vtable->pixel_format_to_gl (ctx, - format, - NULL, /* internal format */ - &gl_format, - &gl_type); - - ctx->texture_driver->prep_gl_for_pixels_download (ctx, - rowstride, - width, - bpp); - - _cogl_bind_gl_texture_transient (tex_2d->gl_target, - tex_2d->gl_texture); - - ctx->texture_driver->gl_get_tex_image (ctx, - tex_2d->gl_target, - gl_format, - gl_type, - data); -} diff --git a/cogl/cogl/driver/gl/cogl-texture-gl-private.h b/cogl/cogl/driver/gl/cogl-texture-gl-private.h deleted file mode 100644 index a8fbd2866..000000000 --- a/cogl/cogl/driver/gl/cogl-texture-gl-private.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2012 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#ifndef _COGL_TEXTURE_GL_PRIVATE_H_ -#define _COGL_TEXTURE_GL_PRIVATE_H_ - -#include "cogl-context.h" - -void -_cogl_texture_gl_prep_alignment_for_pixels_upload (CoglContext *ctx, - int pixels_rowstride); - -void -_cogl_texture_gl_prep_alignment_for_pixels_download (CoglContext *ctx, - int bpp, - int width, - int rowstride); - -void -_cogl_texture_gl_flush_legacy_texobj_wrap_modes (CoglTexture *texture, - unsigned int wrap_mode_s, - unsigned int wrap_mode_t); - -void -_cogl_texture_gl_flush_legacy_texobj_filters (CoglTexture *texture, - unsigned int min_filter, - unsigned int mag_filter); - -void -cogl_texture_gl_set_max_level (CoglTexture *texture, - int max_level); - -void -_cogl_texture_gl_generate_mipmaps (CoglTexture *texture); - -GLenum -_cogl_texture_gl_get_format (CoglTexture *texture); - -#endif /* _COGL_TEXTURE_GL_PRIVATE_H_ */ diff --git a/cogl/cogl/driver/gl/cogl-texture-gl.c b/cogl/cogl/driver/gl/cogl-texture-gl.c deleted file mode 100644 index f1367b0db..000000000 --- a/cogl/cogl/driver/gl/cogl-texture-gl.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2012 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -#include "cogl-config.h" - -#include <strings.h> - -#include "cogl-context-private.h" -#include "cogl-util.h" -#include "driver/gl/cogl-util-gl-private.h" -#include "driver/gl/cogl-texture-gl-private.h" -#include "driver/gl/cogl-pipeline-opengl-private.h" - -static inline int -calculate_alignment (int rowstride) -{ - int alignment = 1 << (ffs (rowstride) - 1); - - return MIN (alignment, 8); -} - -void -_cogl_texture_gl_prep_alignment_for_pixels_upload (CoglContext *ctx, - int pixels_rowstride) -{ - GE( ctx, glPixelStorei (GL_UNPACK_ALIGNMENT, - calculate_alignment (pixels_rowstride)) ); -} - -void -_cogl_texture_gl_prep_alignment_for_pixels_download (CoglContext *ctx, - int bpp, - int width, - int rowstride) -{ - int alignment; - - /* If no padding is needed then we can always use an alignment of 1. - * We want to do this even though it is equivalent to the alignment - * of the rowstride because the Intel driver in Mesa currently has - * an optimisation when reading data into a PBO that only works if - * the alignment is exactly 1. - * - * https://bugs.freedesktop.org/show_bug.cgi?id=46632 - */ - - if (rowstride == bpp * width) - alignment = 1; - else - alignment = calculate_alignment (rowstride); - - GE( ctx, glPixelStorei (GL_PACK_ALIGNMENT, alignment) ); -} - -void -_cogl_texture_gl_flush_legacy_texobj_wrap_modes (CoglTexture *texture, - unsigned int wrap_mode_s, - unsigned int wrap_mode_t) -{ - texture->vtable->gl_flush_legacy_texobj_wrap_modes (texture, - wrap_mode_s, - wrap_mode_t); -} - -void -_cogl_texture_gl_flush_legacy_texobj_filters (CoglTexture *texture, - unsigned int min_filter, - unsigned int mag_filter) -{ - texture->vtable->gl_flush_legacy_texobj_filters (texture, - min_filter, mag_filter); -} - -/* GL and GLES3 have this by default, but GLES2 does not except via extension. - * So really it's probably always available. Even if we used it and it wasn't - * available in some driver then there are no adverse consequences to the - * command simply being ignored... - */ -#ifndef GL_TEXTURE_MAX_LEVEL -#define GL_TEXTURE_MAX_LEVEL 0x813D -#endif - -void -cogl_texture_gl_set_max_level (CoglTexture *texture, - int max_level) -{ - CoglContext *ctx = texture->context; - - if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL)) - { - GLuint gl_handle; - GLenum gl_target; - - cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target); - - texture->max_level_set = max_level; - - _cogl_bind_gl_texture_transient (gl_target, - gl_handle); - - GE( ctx, glTexParameteri (gl_target, - GL_TEXTURE_MAX_LEVEL, texture->max_level_set)); - } -} - -void -_cogl_texture_gl_generate_mipmaps (CoglTexture *texture) -{ - CoglContext *ctx = texture->context; - int n_levels = _cogl_texture_get_n_levels (texture); - GLuint gl_handle; - GLenum gl_target; - - if (texture->max_level_set != n_levels - 1) - cogl_texture_gl_set_max_level (texture, n_levels - 1); - - cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target); - - _cogl_bind_gl_texture_transient (gl_target, - gl_handle); - GE( ctx, glGenerateMipmap (gl_target) ); -} - -GLenum -_cogl_texture_gl_get_format (CoglTexture *texture) -{ - return texture->vtable->get_gl_format (texture); -} diff --git a/cogl/cogl/driver/gl/cogl-util-gl-private.h b/cogl/cogl/driver/gl/cogl-util-gl-private.h deleted file mode 100644 index be8fa1eeb..000000000 --- a/cogl/cogl/driver/gl/cogl-util-gl-private.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2012, 2013 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * Authors: - * Robert Bragg <robert@linux.intel.com> - */ - -#ifndef _COGL_UTIL_GL_PRIVATE_H_ - -#include "cogl-types.h" -#include "cogl-context.h" -#include "cogl-gl-header.h" -#include "cogl-texture.h" - -/* In OpenGL ES context, GL_CONTEXT_LOST has a _KHR prefix */ -#ifndef GL_CONTEXT_LOST -#define GL_CONTEXT_LOST GL_CONTEXT_LOST_KHR -#endif - -#ifdef COGL_GL_DEBUG - -const char * -_cogl_gl_error_to_string (GLenum error_code); - -#define GE(ctx, x) G_STMT_START { \ - GLenum __err; \ - (ctx)->x; \ - while ((__err = (ctx)->glGetError ()) != GL_NO_ERROR && __err != GL_CONTEXT_LOST) \ - { \ - g_warning ("%s: GL error (%d): %s\n", \ - G_STRLOC, \ - __err, \ - _cogl_gl_error_to_string (__err)); \ - } } G_STMT_END - -#define GE_RET(ret, ctx, x) G_STMT_START { \ - GLenum __err; \ - ret = (ctx)->x; \ - while ((__err = (ctx)->glGetError ()) != GL_NO_ERROR && __err != GL_CONTEXT_LOST) \ - { \ - g_warning ("%s: GL error (%d): %s\n", \ - G_STRLOC, \ - __err, \ - _cogl_gl_error_to_string (__err)); \ - } } G_STMT_END - -#else /* !COGL_GL_DEBUG */ - -#define GE(ctx, x) ((ctx)->x) -#define GE_RET(ret, ctx, x) (ret = ((ctx)->x)) - -#endif /* COGL_GL_DEBUG */ - -typedef struct _CoglGLContext { - GArray *texture_units; - int active_texture_unit; - - /* This is used for generated fake unique sampler object numbers - when the sampler object extension is not supported */ - GLuint next_fake_sampler_object_number; -} CoglGLContext; - -CoglGLContext * -_cogl_driver_gl_context (CoglContext *context); - -gboolean -_cogl_driver_gl_context_init (CoglContext *context); - -void -_cogl_driver_gl_context_deinit (CoglContext *context); - -void -_cogl_driver_gl_flush_framebuffer_state (CoglContext *context, - CoglFramebuffer *draw_buffer, - CoglFramebuffer *read_buffer, - CoglFramebufferState state); - -CoglFramebufferDriver * -_cogl_driver_gl_create_framebuffer_driver (CoglContext *context, - CoglFramebuffer *framebuffer, - const CoglFramebufferDriverConfig *driver_config, - GError **error); - -GLenum -_cogl_gl_util_get_error (CoglContext *ctx); - -void -_cogl_gl_util_clear_gl_errors (CoglContext *ctx); - -gboolean -_cogl_gl_util_catch_out_of_memory (CoglContext *ctx, GError **error); - -gboolean -_cogl_driver_gl_is_hardware_accelerated (CoglContext *context); - -/* - * _cogl_context_get_gl_extensions: - * @context: A CoglContext - * - * Return value: a NULL-terminated array of strings representing the - * supported extensions by the current driver. This array is owned - * by the caller and should be freed with g_strfreev(). - */ -char ** -_cogl_context_get_gl_extensions (CoglContext *context); - -const char * -_cogl_context_get_gl_version (CoglContext *context); - -/* Parses a GL version number stored in a string. @version_string must - * point to the beginning of the version number (ie, it can't point to - * the "OpenGL ES" part on GLES). The version number can be followed - * by the end of the string, a space or a full stop. Anything else - * will be treated as invalid. Returns TRUE and sets major_out and - * minor_out if it is successfully parsed or FALSE otherwise. */ -gboolean -_cogl_gl_util_parse_gl_version (const char *version_string, - int *major_out, - int *minor_out); - -CoglGraphicsResetStatus -_cogl_gl_get_graphics_reset_status (CoglContext *context); - -CoglTimestampQuery * -cogl_gl_create_timestamp_query (CoglContext *context); - -void -cogl_gl_free_timestamp_query (CoglContext *context, - CoglTimestampQuery *query); - -int64_t -cogl_gl_timestamp_query_get_time_ns (CoglContext *context, - CoglTimestampQuery *query); - -int64_t -cogl_gl_get_gpu_time_ns (CoglContext *context); - -#ifndef GL_FRAMEBUFFER -#define GL_FRAMEBUFFER 0x8D40 -#endif -#ifndef GL_RENDERBUFFER -#define GL_RENDERBUFFER 0x8D41 -#endif -#ifndef GL_STENCIL_ATTACHMENT -#define GL_STENCIL_ATTACHMENT 0x8D00 -#endif -#ifndef GL_COLOR_ATTACHMENT0 -#define GL_COLOR_ATTACHMENT0 0x8CE0 -#endif -#ifndef GL_FRAMEBUFFER_COMPLETE -#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 -#endif -#ifndef GL_STENCIL_INDEX8 -#define GL_STENCIL_INDEX8 0x8D48 -#endif -#ifndef GL_DEPTH_STENCIL -#define GL_DEPTH_STENCIL 0x84F9 -#endif -#ifndef GL_DEPTH24_STENCIL8 -#define GL_DEPTH24_STENCIL8 0x88F0 -#endif -#ifndef GL_DEPTH_ATTACHMENT -#define GL_DEPTH_ATTACHMENT 0x8D00 -#endif -#ifndef GL_DEPTH_STENCIL_ATTACHMENT -#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A -#endif -#ifndef GL_DEPTH_COMPONENT16 -#define GL_DEPTH_COMPONENT16 0x81A5 -#endif -#ifndef GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE -#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 -#endif -#ifndef GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE -#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 -#endif -#ifndef GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE -#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 -#endif -#ifndef GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE -#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 -#endif -#ifndef GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE -#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 -#endif -#ifndef GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE -#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 -#endif -#ifndef GL_READ_FRAMEBUFFER -#define GL_READ_FRAMEBUFFER 0x8CA8 -#endif -#ifndef GL_DRAW_FRAMEBUFFER -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#endif -#ifndef GL_TEXTURE_SAMPLES_IMG -#define GL_TEXTURE_SAMPLES_IMG 0x9136 -#endif -#ifndef GL_PACK_INVERT_MESA -#define GL_PACK_INVERT_MESA 0x8758 -#endif -#ifndef GL_PACK_REVERSE_ROW_ORDER_ANGLE -#define GL_PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4 -#endif -#ifndef GL_BACK_LEFT -#define GL_BACK_LEFT 0x0402 -#endif -#ifndef GL_BACK_RIGHT -#define GL_BACK_RIGHT 0x0403 -#endif - -#ifndef GL_COLOR -#define GL_COLOR 0x1800 -#endif -#ifndef GL_DEPTH -#define GL_DEPTH 0x1801 -#endif -#ifndef GL_STENCIL -#define GL_STENCIL 0x1802 -#endif - -#ifndef GL_TIMESTAMP -#define GL_TIMESTAMP 0x8E28 -#endif -#ifndef GL_QUERY_RESULT -#define GL_QUERY_RESULT 0x8866 -#endif - -#endif /* _COGL_UTIL_GL_PRIVATE_H_ */ diff --git a/cogl/cogl/driver/gl/cogl-util-gl.c b/cogl/cogl/driver/gl/cogl-util-gl.c deleted file mode 100644 index 80c417913..000000000 --- a/cogl/cogl/driver/gl/cogl-util-gl.c +++ /dev/null @@ -1,562 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2012, 2013 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * Authors: - * Robert Bragg <robert@linux.intel.com> - */ - -#include "cogl-config.h" - -#include "cogl-types.h" -#include "cogl-context-private.h" -#include "driver/gl/cogl-framebuffer-gl-private.h" -#include "driver/gl/cogl-gl-framebuffer-fbo.h" -#include "driver/gl/cogl-gl-framebuffer-back.h" -#include "driver/gl/cogl-pipeline-opengl-private.h" -#include "driver/gl/cogl-util-gl-private.h" - -/* This is a relatively new extension */ -#ifndef GL_PURGED_CONTEXT_RESET_NV -#define GL_PURGED_CONTEXT_RESET_NV 0x92BB -#endif - -/* These aren't defined in the GLES2 headers */ -#ifndef GL_GUILTY_CONTEXT_RESET_ARB -#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253 -#endif - -#ifndef GL_INNOCENT_CONTEXT_RESET_ARB -#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254 -#endif - -#ifndef GL_UNKNOWN_CONTEXT_RESET_ARB -#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255 -#endif - -#ifdef COGL_GL_DEBUG -/* GL error to string conversion */ -static const struct { - GLuint error_code; - const char *error_string; -} gl_errors[] = { - { GL_NO_ERROR, "No error" }, - { GL_INVALID_ENUM, "Invalid enumeration value" }, - { GL_INVALID_VALUE, "Invalid value" }, - { GL_INVALID_OPERATION, "Invalid operation" }, -#ifdef HAVE_COGL_GL - { GL_STACK_OVERFLOW, "Stack overflow" }, - { GL_STACK_UNDERFLOW, "Stack underflow" }, -#endif - { GL_OUT_OF_MEMORY, "Out of memory" }, - -#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT - { GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "Invalid framebuffer operation" } -#endif -}; - -static const unsigned int n_gl_errors = G_N_ELEMENTS (gl_errors); - -const char * -_cogl_gl_error_to_string (GLenum error_code) -{ - int i; - - for (i = 0; i < n_gl_errors; i++) - { - if (gl_errors[i].error_code == error_code) - return gl_errors[i].error_string; - } - - return "Unknown GL error"; -} -#endif /* COGL_GL_DEBUG */ - -CoglGLContext * -_cogl_driver_gl_context (CoglContext *context) -{ - return context->driver_context; -} - -gboolean -_cogl_driver_gl_context_init (CoglContext *context) -{ - CoglGLContext *gl_context; - - if (!context->driver_context) - context->driver_context = g_new0 (CoglContext, 1); - - gl_context = _cogl_driver_gl_context (context); - if (!gl_context) - return FALSE; - - gl_context->next_fake_sampler_object_number = 1; - gl_context->texture_units = - g_array_new (FALSE, FALSE, sizeof (CoglTextureUnit)); - - /* See cogl-pipeline.c for more details about why we leave texture unit 1 - * active by default... */ - gl_context->active_texture_unit = 1; - GE (context, glActiveTexture (GL_TEXTURE1)); - - return TRUE; -} - -void -_cogl_driver_gl_context_deinit (CoglContext *context) -{ - _cogl_destroy_texture_units (context); - g_free (context->driver_context); -} - -CoglFramebufferDriver * -_cogl_driver_gl_create_framebuffer_driver (CoglContext *context, - CoglFramebuffer *framebuffer, - const CoglFramebufferDriverConfig *driver_config, - GError **error) -{ - g_return_val_if_fail (driver_config, NULL); - - switch (driver_config->type) - { - case COGL_FRAMEBUFFER_DRIVER_TYPE_FBO: - { - CoglGlFramebufferFbo *gl_framebuffer_fbo; - - gl_framebuffer_fbo = cogl_gl_framebuffer_fbo_new (framebuffer, - driver_config, - error); - if (!gl_framebuffer_fbo) - return NULL; - - return COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_fbo); - } - case COGL_FRAMEBUFFER_DRIVER_TYPE_BACK: - { - CoglGlFramebufferBack *gl_framebuffer_back; - - gl_framebuffer_back = cogl_gl_framebuffer_back_new (framebuffer, - driver_config, - error); - if (!gl_framebuffer_back) - return NULL; - - return COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_back); - } - } - - g_assert_not_reached (); - return NULL; -} - -void -_cogl_driver_gl_flush_framebuffer_state (CoglContext *ctx, - CoglFramebuffer *draw_buffer, - CoglFramebuffer *read_buffer, - CoglFramebufferState state) -{ - CoglGlFramebuffer *draw_gl_framebuffer; - CoglGlFramebuffer *read_gl_framebuffer; - unsigned long differences; - - /* We can assume that any state that has changed for the current - * framebuffer is different to the currently flushed value. */ - differences = ctx->current_draw_buffer_changes; - - /* Any state of the current framebuffer that hasn't already been - * flushed is assumed to be unknown so we will always flush that - * state if asked. */ - differences |= ~ctx->current_draw_buffer_state_flushed; - - /* We only need to consider the state we've been asked to flush */ - differences &= state; - - if (ctx->current_draw_buffer != draw_buffer) - { - /* If the previous draw buffer is NULL then we'll assume - everything has changed. This can happen if a framebuffer is - destroyed while it is the last flushed draw buffer. In that - case the framebuffer destructor will set - ctx->current_draw_buffer to NULL */ - if (ctx->current_draw_buffer == NULL) - differences |= state; - else - /* NB: we only need to compare the state we're being asked to flush - * and we don't need to compare the state we've already decided - * we will definitely flush... */ - differences |= _cogl_framebuffer_compare (ctx->current_draw_buffer, - draw_buffer, - state & ~differences); - - /* NB: we don't take a reference here, to avoid a circular - * reference. */ - ctx->current_draw_buffer = draw_buffer; - ctx->current_draw_buffer_state_flushed = 0; - } - - if (ctx->current_read_buffer != read_buffer && - state & COGL_FRAMEBUFFER_STATE_BIND) - { - differences |= COGL_FRAMEBUFFER_STATE_BIND; - /* NB: we don't take a reference here, to avoid a circular - * reference. */ - ctx->current_read_buffer = read_buffer; - } - - if (!differences) - return; - - /* Lazily ensure the framebuffers have been allocated */ - if (G_UNLIKELY (!cogl_framebuffer_is_allocated (draw_buffer))) - cogl_framebuffer_allocate (draw_buffer, NULL); - if (G_UNLIKELY (!cogl_framebuffer_is_allocated (read_buffer))) - cogl_framebuffer_allocate (read_buffer, NULL); - - draw_gl_framebuffer = - COGL_GL_FRAMEBUFFER (cogl_framebuffer_get_driver (draw_buffer)); - read_gl_framebuffer = - COGL_GL_FRAMEBUFFER (cogl_framebuffer_get_driver (read_buffer)); - - /* We handle buffer binding separately since the method depends on whether - * we are binding the same buffer for read and write or not unlike all - * other state that only relates to the draw_buffer. */ - if (differences & COGL_FRAMEBUFFER_STATE_BIND) - { - if (draw_buffer == read_buffer) - { - cogl_gl_framebuffer_bind (draw_gl_framebuffer, GL_FRAMEBUFFER); - } - else - { - /* NB: Currently we only take advantage of binding separate - * read/write buffers for framebuffer blit purposes. */ - g_return_if_fail (cogl_has_feature - (ctx, COGL_FEATURE_ID_BLIT_FRAMEBUFFER)); - - cogl_gl_framebuffer_bind (draw_gl_framebuffer, GL_DRAW_FRAMEBUFFER); - cogl_gl_framebuffer_bind (read_gl_framebuffer, GL_READ_FRAMEBUFFER); - } - - differences &= ~COGL_FRAMEBUFFER_STATE_BIND; - } - - cogl_gl_framebuffer_flush_state_differences (draw_gl_framebuffer, - differences); - - ctx->current_draw_buffer_state_flushed |= state; - ctx->current_draw_buffer_changes &= ~state; -} - -GLenum -_cogl_gl_util_get_error (CoglContext *ctx) -{ - GLenum gl_error = ctx->glGetError (); - - if (gl_error != GL_NO_ERROR && gl_error != GL_CONTEXT_LOST) - return gl_error; - else - return GL_NO_ERROR; -} - -void -_cogl_gl_util_clear_gl_errors (CoglContext *ctx) -{ - GLenum gl_error; - - while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR && gl_error != GL_CONTEXT_LOST) - ; -} - -gboolean -_cogl_gl_util_catch_out_of_memory (CoglContext *ctx, GError **error) -{ - GLenum gl_error; - gboolean out_of_memory = FALSE; - - while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR && gl_error != GL_CONTEXT_LOST) - { - if (gl_error == GL_OUT_OF_MEMORY) - out_of_memory = TRUE; -#ifdef COGL_GL_DEBUG - else - { - g_warning ("%s: GL error (%d): %s\n", - G_STRLOC, - gl_error, - _cogl_gl_error_to_string (gl_error)); - } -#endif - } - - if (out_of_memory) - { - g_set_error_literal (error, COGL_SYSTEM_ERROR, - COGL_SYSTEM_ERROR_NO_MEMORY, - "Out of memory"); - return TRUE; - } - - return FALSE; -} - -char ** -_cogl_context_get_gl_extensions (CoglContext *context) -{ - const char *env_disabled_extensions; - char **ret; - - /* In GL 3, querying GL_EXTENSIONS is deprecated so we have to build - * the array using glGetStringi instead */ -#ifdef HAVE_COGL_GL - if (context->driver == COGL_DRIVER_GL3) - { - int num_extensions, i; - - context->glGetIntegerv (GL_NUM_EXTENSIONS, &num_extensions); - - ret = g_malloc (sizeof (char *) * (num_extensions + 1)); - - for (i = 0; i < num_extensions; i++) - { - const char *ext = - (const char *) context->glGetStringi (GL_EXTENSIONS, i); - ret[i] = g_strdup (ext); - } - - ret[num_extensions] = NULL; - } - else -#endif - { - const char *all_extensions = - (const char *) context->glGetString (GL_EXTENSIONS); - - ret = g_strsplit (all_extensions, " ", 0 /* max tokens */); - } - - if ((env_disabled_extensions = g_getenv ("COGL_DISABLE_GL_EXTENSIONS"))) - { - char **split_env_disabled_extensions; - char **src, **dst; - - if (env_disabled_extensions) - split_env_disabled_extensions = - g_strsplit (env_disabled_extensions, - ",", - 0 /* no max tokens */); - else - split_env_disabled_extensions = NULL; - - for (dst = ret, src = ret; - *src; - src++) - { - char **d; - - if (split_env_disabled_extensions) - for (d = split_env_disabled_extensions; *d; d++) - if (!strcmp (*src, *d)) - goto disabled; - - *(dst++) = *src; - continue; - - disabled: - g_free (*src); - continue; - } - - *dst = NULL; - - if (split_env_disabled_extensions) - g_strfreev (split_env_disabled_extensions); - } - - return ret; -} - -const char * -_cogl_context_get_gl_version (CoglContext *context) -{ - const char *version_override; - - if ((version_override = g_getenv ("COGL_OVERRIDE_GL_VERSION"))) - return version_override; - else - return (const char *) context->glGetString (GL_VERSION); - -} - -gboolean -_cogl_gl_util_parse_gl_version (const char *version_string, - int *major_out, - int *minor_out) -{ - const char *major_end, *minor_end; - int major = 0, minor = 0; - - /* Extract the major number */ - for (major_end = version_string; *major_end >= '0' - && *major_end <= '9'; major_end++) - major = (major * 10) + *major_end - '0'; - /* If there were no digits or the major number isn't followed by a - dot then it is invalid */ - if (major_end == version_string || *major_end != '.') - return FALSE; - - /* Extract the minor number */ - for (minor_end = major_end + 1; *minor_end >= '0' - && *minor_end <= '9'; minor_end++) - minor = (minor * 10) + *minor_end - '0'; - /* If there were no digits or there is an unexpected character then - it is invalid */ - if (minor_end == major_end + 1 - || (*minor_end && *minor_end != ' ' && *minor_end != '.')) - return FALSE; - - *major_out = major; - *minor_out = minor; - - return TRUE; -} - -/* - * This should arguably use something like GLX_MESA_query_renderer, but - * a) that's GLX-only, and you could add it to EGL too but - * b) that'd make this a winsys query when really it's not a property of - * the winsys but the renderer, and - * c) only Mesa really supports it anyway, and - * d) Mesa is the only software renderer of interest. - * - * So instead just check a list of known software renderer strings. - */ -gboolean -_cogl_driver_gl_is_hardware_accelerated (CoglContext *ctx) -{ - const char *renderer = (const char *) ctx->glGetString (GL_RENDERER); - gboolean software; - - if (!renderer) - { - g_warning ("OpenGL driver returned NULL as the renderer, " - "something is wrong"); - return TRUE; - } - - software = strstr (renderer, "llvmpipe") != NULL || - strstr (renderer, "softpipe") != NULL || - strstr (renderer, "software rasterizer") != NULL || - strstr (renderer, "Software Rasterizer") != NULL || - strstr (renderer, "SWR"); - - return !software; -} - -CoglGraphicsResetStatus -_cogl_gl_get_graphics_reset_status (CoglContext *context) -{ - if (!context->glGetGraphicsResetStatus) - return COGL_GRAPHICS_RESET_STATUS_NO_ERROR; - - switch (context->glGetGraphicsResetStatus ()) - { - case GL_GUILTY_CONTEXT_RESET_ARB: - return COGL_GRAPHICS_RESET_STATUS_GUILTY_CONTEXT_RESET; - - case GL_INNOCENT_CONTEXT_RESET_ARB: - return COGL_GRAPHICS_RESET_STATUS_INNOCENT_CONTEXT_RESET; - - case GL_UNKNOWN_CONTEXT_RESET_ARB: - return COGL_GRAPHICS_RESET_STATUS_UNKNOWN_CONTEXT_RESET; - - case GL_PURGED_CONTEXT_RESET_NV: - return COGL_GRAPHICS_RESET_STATUS_PURGED_CONTEXT_RESET; - - default: - return COGL_GRAPHICS_RESET_STATUS_NO_ERROR; - } -} - -CoglTimestampQuery * -cogl_gl_create_timestamp_query (CoglContext *context) -{ - CoglTimestampQuery *query; - - g_return_val_if_fail (cogl_has_feature (context, - COGL_FEATURE_ID_TIMESTAMP_QUERY), - NULL); - - query = g_new0 (CoglTimestampQuery, 1); - - GE (context, glGenQueries (1, &query->id)); - GE (context, glQueryCounter (query->id, GL_TIMESTAMP)); - - /* Flush right away so GL knows about our timestamp query. - * - * E.g. the direct scanout path doesn't call SwapBuffers or any other - * glFlush-inducing operation, and skipping explicit glFlush here results in - * the timestamp query being placed at the point of glGetQueryObject much - * later, resulting in a GPU timestamp much later on in time. - */ - GE (context, glFlush ()); - - return query; -} - -void -cogl_gl_free_timestamp_query (CoglContext *context, - CoglTimestampQuery *query) -{ - GE (context, glDeleteQueries (1, &query->id)); - g_free (query); -} - -int64_t -cogl_gl_timestamp_query_get_time_ns (CoglContext *context, - CoglTimestampQuery *query) -{ - int64_t query_time_ns; - - GE (context, glGetQueryObjecti64v (query->id, - GL_QUERY_RESULT, - &query_time_ns)); - - return query_time_ns; -} - -int64_t -cogl_gl_get_gpu_time_ns (CoglContext *context) -{ - int64_t gpu_time_ns; - - g_return_val_if_fail (cogl_has_feature (context, - COGL_FEATURE_ID_GET_GPU_TIME), - 0); - - GE (context, glGetInteger64v (GL_TIMESTAMP, &gpu_time_ns)); - return gpu_time_ns; -} diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c deleted file mode 100644 index ef4a61a09..000000000 --- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2007,2008,2009 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - */ - -#include "cogl-config.h" - -#include <string.h> - -#include "cogl-private.h" -#include "cogl-context-private.h" -#include "cogl-feature-private.h" -#include "cogl-renderer-private.h" -#include "driver/gl/cogl-util-gl-private.h" -#include "driver/gl/cogl-framebuffer-gl-private.h" -#include "driver/gl/cogl-texture-2d-gl-private.h" -#include "driver/gl/cogl-attribute-gl-private.h" -#include "driver/gl/cogl-clip-stack-gl-private.h" -#include "driver/gl/cogl-buffer-gl-private.h" -#include "driver/gl/cogl-pipeline-opengl-private.h" - -static gboolean -_cogl_driver_gl_real_context_init (CoglContext *context) -{ - - _cogl_driver_gl_context_init (context); - - if ((context->driver == COGL_DRIVER_GL3)) - { - GLuint vertex_array; - - /* In a forward compatible context, GL 3 doesn't support rendering - * using the default vertex array object. Cogl doesn't use vertex - * array objects yet so for now we just create a dummy array - * object that we will use as our own default object. Eventually - * it could be good to attach the vertex array objects to - * CoglPrimitives */ - context->glGenVertexArrays (1, &vertex_array); - context->glBindVertexArray (vertex_array); - } - - /* As far as I can tell, GL_POINT_SPRITE doesn't have any effect - unless GL_COORD_REPLACE is enabled for an individual layer. - Therefore it seems like it should be ok to just leave it enabled - all the time instead of having to have a set property on each - pipeline to track whether any layers have point sprite coords - enabled. We don't need to do this for GL3 or GLES2 because point - sprites are handled using a builtin varying in the shader. */ - if (context->driver == COGL_DRIVER_GL) - GE (context, glEnable (GL_POINT_SPRITE)); - - /* There's no enable for this in GLES2, it's always on */ - if (context->driver == COGL_DRIVER_GL || - context->driver == COGL_DRIVER_GL3) - GE (context, glEnable (GL_PROGRAM_POINT_SIZE) ); - - return TRUE; -} - -static gboolean -_cogl_driver_pixel_format_from_gl_internal (CoglContext *context, - GLenum gl_int_format, - CoglPixelFormat *out_format) -{ - /* It doesn't really matter we convert to exact same - format (some have no cogl match anyway) since format - is re-matched against cogl when getting or setting - texture image data. - */ - - switch (gl_int_format) - { - case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8: - case GL_ALPHA12: case GL_ALPHA16: - /* Cogl only supports one single-component texture so if we have - * ended up with a red texture then it is probably being used as - * a component-alpha texture */ - case GL_RED: - - *out_format = COGL_PIXEL_FORMAT_A_8; - return TRUE; - - case GL_LUMINANCE: case GL_LUMINANCE4: case GL_LUMINANCE8: - case GL_LUMINANCE12: case GL_LUMINANCE16: - - *out_format = COGL_PIXEL_FORMAT_G_8; - return TRUE; - - case GL_RG: - *out_format = COGL_PIXEL_FORMAT_RG_88; - return TRUE; - - case GL_RGB: case GL_RGB4: case GL_RGB5: case GL_RGB8: - case GL_RGB10: case GL_RGB12: case GL_RGB16: case GL_R3_G3_B2: - - *out_format = COGL_PIXEL_FORMAT_RGB_888; - return TRUE; - - case GL_RGBA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1: - case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: - - *out_format = COGL_PIXEL_FORMAT_RGBA_8888; - return TRUE; - } - - return FALSE; -} - -static CoglPixelFormat -_cogl_driver_pixel_format_to_gl (CoglContext *context, - CoglPixelFormat format, - GLenum *out_glintformat, - GLenum *out_glformat, - GLenum *out_gltype) -{ - CoglPixelFormat required_format; - GLenum glintformat = 0; - GLenum glformat = 0; - GLenum gltype = 0; - - required_format = format; - - /* Find GL equivalents */ - switch (format) - { - case COGL_PIXEL_FORMAT_A_8: - /* If the driver doesn't natively support alpha textures then we - * will use a red component texture with a swizzle to implement - * the texture */ - if (_cogl_has_private_feature - (context, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) == 0) - { - glintformat = GL_RED; - glformat = GL_RED; - } - else - { - glintformat = GL_ALPHA; - glformat = GL_ALPHA; - } - gltype = GL_UNSIGNED_BYTE; - break; - case COGL_PIXEL_FORMAT_G_8: - glintformat = GL_LUMINANCE; - glformat = GL_LUMINANCE; - gltype = GL_UNSIGNED_BYTE; - break; - - case COGL_PIXEL_FORMAT_RG_88: - if (cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_RG)) - { - glintformat = GL_RG; - glformat = GL_RG; - } - else - { - /* If red-green textures aren't supported then we'll use RGB - * as an internal format. Note this should only end up - * mattering for downloading the data because Cogl will - * refuse to allocate a texture with RG components if RG - * textures aren't supported */ - glintformat = GL_RGB; - glformat = GL_RGB; - required_format = COGL_PIXEL_FORMAT_RGB_888; - } - gltype = GL_UNSIGNED_BYTE; - break; - - case COGL_PIXEL_FORMAT_RGB_888: - glintformat = GL_RGB; - glformat = GL_RGB; - gltype = GL_UNSIGNED_BYTE; - break; - case COGL_PIXEL_FORMAT_BGR_888: - glintformat = GL_RGB; - glformat = GL_BGR; - gltype = GL_UNSIGNED_BYTE; - break; - case COGL_PIXEL_FORMAT_RGBA_8888: - case COGL_PIXEL_FORMAT_RGBA_8888_PRE: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_BYTE; - break; - case COGL_PIXEL_FORMAT_BGRA_8888: - case COGL_PIXEL_FORMAT_BGRA_8888_PRE: - glintformat = GL_RGBA; - glformat = GL_BGRA; - gltype = GL_UNSIGNED_BYTE; - break; - - /* The following two types of channel ordering - * have no GL equivalent unless defined using - * system word byte ordering */ - case COGL_PIXEL_FORMAT_ARGB_8888: - case COGL_PIXEL_FORMAT_ARGB_8888_PRE: - glintformat = GL_RGBA; - glformat = GL_BGRA; -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - gltype = GL_UNSIGNED_INT_8_8_8_8; -#else - gltype = GL_UNSIGNED_INT_8_8_8_8_REV; -#endif - break; - - case COGL_PIXEL_FORMAT_ABGR_8888: - case COGL_PIXEL_FORMAT_ABGR_8888_PRE: - glintformat = GL_RGBA; - glformat = GL_RGBA; -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - gltype = GL_UNSIGNED_INT_8_8_8_8; -#else - gltype = GL_UNSIGNED_INT_8_8_8_8_REV; -#endif - break; - - case COGL_PIXEL_FORMAT_RGBA_1010102: - case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_INT_10_10_10_2; - break; - - case COGL_PIXEL_FORMAT_BGRA_1010102: - case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: - glintformat = GL_RGBA; - glformat = GL_BGRA; - gltype = GL_UNSIGNED_INT_10_10_10_2; - break; - - case COGL_PIXEL_FORMAT_ABGR_2101010: - case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_INT_2_10_10_10_REV; - break; - - case COGL_PIXEL_FORMAT_ARGB_2101010: - case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: - glintformat = GL_RGBA; - glformat = GL_BGRA; - gltype = GL_UNSIGNED_INT_2_10_10_10_REV; - break; - - /* The following three types of channel ordering - * are always defined using system word byte - * ordering (even according to GLES spec) */ - case COGL_PIXEL_FORMAT_RGB_565: - glintformat = GL_RGB; - glformat = GL_RGB; - gltype = GL_UNSIGNED_SHORT_5_6_5; - break; - case COGL_PIXEL_FORMAT_RGBA_4444: - case COGL_PIXEL_FORMAT_RGBA_4444_PRE: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_SHORT_4_4_4_4; - break; - case COGL_PIXEL_FORMAT_RGBA_5551: - case COGL_PIXEL_FORMAT_RGBA_5551_PRE: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_SHORT_5_5_5_1; - break; - - case COGL_PIXEL_FORMAT_RGBA_FP_16161616: - case COGL_PIXEL_FORMAT_RGBA_FP_16161616_PRE: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_HALF_FLOAT; - break; - case COGL_PIXEL_FORMAT_BGRA_FP_16161616: - case COGL_PIXEL_FORMAT_BGRA_FP_16161616_PRE: - glintformat = GL_RGBA; - glformat = GL_BGRA; - gltype = GL_HALF_FLOAT; - break; - case COGL_PIXEL_FORMAT_ARGB_FP_16161616: - case COGL_PIXEL_FORMAT_ARGB_FP_16161616_PRE: - glintformat = GL_RGBA; - glformat = GL_BGRA; - gltype = GL_HALF_FLOAT; - break; - case COGL_PIXEL_FORMAT_ABGR_FP_16161616: - case COGL_PIXEL_FORMAT_ABGR_FP_16161616_PRE: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_HALF_FLOAT; - break; - - case COGL_PIXEL_FORMAT_DEPTH_16: - glintformat = GL_DEPTH_COMPONENT16; - glformat = GL_DEPTH_COMPONENT; - gltype = GL_UNSIGNED_SHORT; - break; - case COGL_PIXEL_FORMAT_DEPTH_32: - glintformat = GL_DEPTH_COMPONENT32; - glformat = GL_DEPTH_COMPONENT; - gltype = GL_UNSIGNED_INT; - break; - - case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8: - glintformat = GL_DEPTH_STENCIL; - glformat = GL_DEPTH_STENCIL; - gltype = GL_UNSIGNED_INT_24_8; - break; - - case COGL_PIXEL_FORMAT_ANY: - case COGL_PIXEL_FORMAT_YUV: - g_assert_not_reached (); - break; - } - - /* All of the pixel formats are handled above so if this hits then - we've been given an invalid pixel format */ - g_assert (glformat != 0); - - if (out_glintformat != NULL) - *out_glintformat = glintformat; - if (out_glformat != NULL) - *out_glformat = glformat; - if (out_gltype != NULL) - *out_gltype = gltype; - - return required_format; -} - -static gboolean -_cogl_get_gl_version (CoglContext *ctx, - int *major_out, - int *minor_out) -{ - const char *version_string; - - /* Get the OpenGL version number */ - if ((version_string = _cogl_context_get_gl_version (ctx)) == NULL) - return FALSE; - - return _cogl_gl_util_parse_gl_version (version_string, major_out, minor_out); -} - -static gboolean -check_gl_version (CoglContext *ctx, - char **gl_extensions, - GError **error) -{ - int major, minor; - - if (!_cogl_get_gl_version (ctx, &major, &minor)) - { - g_set_error (error, - COGL_DRIVER_ERROR, - COGL_DRIVER_ERROR_UNKNOWN_VERSION, - "The OpenGL version could not be determined"); - return FALSE; - } - - /* We require GLSL 1.20, which is implied by OpenGL 2.1. */ - if (!COGL_CHECK_GL_VERSION (major, minor, 2, 1)) - { - g_set_error (error, - COGL_DRIVER_ERROR, - COGL_DRIVER_ERROR_INVALID_VERSION, - "OpenGL 2.1 or better is required"); - return FALSE; - } - - return TRUE; -} - -static gboolean -_cogl_driver_update_features (CoglContext *ctx, - GError **error) -{ - unsigned long private_features - [COGL_FLAGS_N_LONGS_FOR_SIZE (COGL_N_PRIVATE_FEATURES)] = { 0 }; - char **gl_extensions; - const char *glsl_version; - int gl_major = 0, gl_minor = 0; - int i; - - /* We have to special case getting the pointer to the glGetString* - functions because we need to use them to determine what functions - we can expect */ - ctx->glGetString = - (void *) _cogl_renderer_get_proc_address (ctx->display->renderer, - "glGetString", - TRUE); - ctx->glGetStringi = - (void *) _cogl_renderer_get_proc_address (ctx->display->renderer, - "glGetStringi", - TRUE); - ctx->glGetIntegerv = - (void *) _cogl_renderer_get_proc_address (ctx->display->renderer, - "glGetIntegerv", - TRUE); - - gl_extensions = _cogl_context_get_gl_extensions (ctx); - - if (!check_gl_version (ctx, gl_extensions, error)) - return FALSE; - - if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WINSYS))) - { - char *all_extensions = g_strjoinv (" ", gl_extensions); - - COGL_NOTE (WINSYS, - "Checking features\n" - " GL_VENDOR: %s\n" - " GL_RENDERER: %s\n" - " GL_VERSION: %s\n" - " GL_EXTENSIONS: %s", - ctx->glGetString (GL_VENDOR), - ctx->glGetString (GL_RENDERER), - _cogl_context_get_gl_version (ctx), - all_extensions); - - g_free (all_extensions); - } - - _cogl_get_gl_version (ctx, &gl_major, &gl_minor); - - ctx->glsl_major = 1; - ctx->glsl_minor = 2; - ctx->glsl_version_to_use = 120; - - glsl_version = (char *)ctx->glGetString (GL_SHADING_LANGUAGE_VERSION); - _cogl_gl_util_parse_gl_version (glsl_version, - &ctx->glsl_major, - &ctx->glsl_minor); - - COGL_FLAGS_SET (ctx->features, - COGL_FEATURE_ID_UNSIGNED_INT_INDICES, TRUE); - - _cogl_feature_check_ext_functions (ctx, - gl_major, - gl_minor, - gl_extensions); - - if (_cogl_check_extension ("GL_MESA_pack_invert", gl_extensions)) - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_MESA_PACK_INVERT, TRUE); - - if (!ctx->glGenRenderbuffers) - { - g_set_error (error, - COGL_DRIVER_ERROR, - COGL_DRIVER_ERROR_NO_SUITABLE_DRIVER_FOUND, - "Framebuffer objects are required to use the GL driver"); - return FALSE; - } - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS, - TRUE); - - if (ctx->glBlitFramebuffer) - COGL_FLAGS_SET (ctx->features, - COGL_FEATURE_ID_BLIT_FRAMEBUFFER, TRUE); - - COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_PBOS, TRUE); - - COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ, TRUE); - COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, TRUE); - - if (ctx->glEGLImageTargetTexture2D) - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE, TRUE); - - if (_cogl_check_extension ("GL_EXT_packed_depth_stencil", gl_extensions)) - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL, TRUE); - - if (ctx->glGenSamplers) - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS, TRUE); - - if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 3) || - _cogl_check_extension ("GL_ARB_texture_swizzle", gl_extensions) || - _cogl_check_extension ("GL_EXT_texture_swizzle", gl_extensions)) - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE, TRUE); - - if (ctx->driver == COGL_DRIVER_GL) - { - /* Features which are not available in GL 3 */ - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_ALPHA_TEXTURES, TRUE); - } - - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_READ_PIXELS_ANY_FORMAT, TRUE); - COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_ANY_GL, TRUE); - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_FORMAT_CONVERSION, TRUE); - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_QUERY_TEXTURE_PARAMETERS, TRUE); - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL, TRUE); - - if (ctx->glFenceSync) - COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_FENCE, TRUE); - - if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 0) || - _cogl_check_extension ("GL_ARB_texture_rg", gl_extensions)) - COGL_FLAGS_SET (ctx->features, - COGL_FEATURE_ID_TEXTURE_RG, - TRUE); - - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_RGBA1010102, TRUE); - - if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 0)) - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_HALF_FLOAT, - TRUE); - - if (ctx->glGenQueries && ctx->glQueryCounter) - COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TIMESTAMP_QUERY, TRUE); - - if (ctx->glGetInteger64v) - COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_GET_GPU_TIME, TRUE); - - /* Cache features */ - for (i = 0; i < G_N_ELEMENTS (private_features); i++) - ctx->private_features[i] |= private_features[i]; - - g_strfreev (gl_extensions); - - if (!COGL_FLAGS_GET (private_features, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) && - !COGL_FLAGS_GET (private_features, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE)) - { - g_set_error (error, - COGL_DRIVER_ERROR, - COGL_DRIVER_ERROR_NO_SUITABLE_DRIVER_FOUND, - "The GL_ARB_texture_swizzle extension is required " - "to use the GL3 driver"); - return FALSE; - } - - return TRUE; -} - -const CoglDriverVtable -_cogl_driver_gl = - { - _cogl_driver_gl_real_context_init, - _cogl_driver_gl_context_deinit, - _cogl_driver_gl_is_hardware_accelerated, - _cogl_gl_get_graphics_reset_status, - _cogl_driver_pixel_format_from_gl_internal, - _cogl_driver_pixel_format_to_gl, - _cogl_driver_update_features, - _cogl_driver_gl_create_framebuffer_driver, - _cogl_driver_gl_flush_framebuffer_state, - _cogl_texture_2d_gl_free, - _cogl_texture_2d_gl_can_create, - _cogl_texture_2d_gl_init, - _cogl_texture_2d_gl_allocate, - _cogl_texture_2d_gl_copy_from_framebuffer, - _cogl_texture_2d_gl_get_gl_handle, - _cogl_texture_2d_gl_generate_mipmap, - _cogl_texture_2d_gl_copy_from_bitmap, - _cogl_texture_2d_gl_is_get_data_supported, - _cogl_texture_2d_gl_get_data, - _cogl_gl_flush_attributes_state, - _cogl_clip_stack_gl_flush, - _cogl_buffer_gl_create, - _cogl_buffer_gl_destroy, - _cogl_buffer_gl_map_range, - _cogl_buffer_gl_unmap, - _cogl_buffer_gl_set_data, - _cogl_sampler_gl_init, - _cogl_sampler_gl_free, - _cogl_gl_set_uniform, /* XXX name is weird... */ - cogl_gl_create_timestamp_query, - cogl_gl_free_timestamp_query, - cogl_gl_timestamp_query_get_time_ns, - cogl_gl_get_gpu_time_ns, - }; diff --git a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c deleted file mode 100644 index 5e95d05a7..000000000 --- a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2007,2008,2009 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Matthew Allum <mallum@openedhand.com> - * Neil Roberts <neil@linux.intel.com> - * Robert Bragg <robert@linux.intel.com> - */ - -#include "cogl-config.h" - -#include "cogl-private.h" -#include "cogl-util.h" -#include "cogl-bitmap.h" -#include "cogl-bitmap-private.h" -#include "cogl-texture-private.h" -#include "cogl-pipeline.h" -#include "cogl-context-private.h" -#include "cogl-object-private.h" -#include "driver/gl/cogl-pipeline-opengl-private.h" -#include "driver/gl/cogl-util-gl-private.h" -#include "driver/gl/cogl-texture-gl-private.h" -#include "driver/gl/cogl-bitmap-gl-private.h" - -#include <string.h> -#include <stdlib.h> -#include <math.h> - -#ifndef GL_TEXTURE_SWIZZLE_RGBA -#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 -#endif - -static GLuint -_cogl_texture_driver_gen (CoglContext *ctx, - GLenum gl_target, - CoglPixelFormat internal_format) -{ - GLuint tex; - - GE (ctx, glGenTextures (1, &tex)); - - _cogl_bind_gl_texture_transient (gl_target, tex); - - switch (gl_target) - { - case GL_TEXTURE_2D: - /* In case automatic mipmap generation gets disabled for this - * texture but a minification filter depending on mipmap - * interpolation is selected then we initialize the max mipmap - * level to 0 so OpenGL will consider the texture storage to be - * "complete". - */ -#ifdef HAVE_COGL_GL - if (_cogl_has_private_feature - (ctx, COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL)) - GE( ctx, glTexParameteri (gl_target, GL_TEXTURE_MAX_LEVEL, 0)); -#endif - - /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */ - GE( ctx, glTexParameteri (gl_target, - GL_TEXTURE_MIN_FILTER, - GL_LINEAR) ); - break; - - case GL_TEXTURE_RECTANGLE_ARB: - /* Texture rectangles already default to GL_LINEAR so nothing - needs to be done */ - break; - - default: - g_assert_not_reached(); - } - - /* If the driver doesn't support alpha textures directly then we'll - * fake them by setting the swizzle parameters */ - if (internal_format == COGL_PIXEL_FORMAT_A_8 && - !_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) && - _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_SWIZZLE)) - { - static const GLint red_swizzle[] = { GL_ZERO, GL_ZERO, GL_ZERO, GL_RED }; - - GE( ctx, glTexParameteriv (gl_target, - GL_TEXTURE_SWIZZLE_RGBA, - red_swizzle) ); - } - - return tex; -} - -/* OpenGL - unlike GLES - can upload a sub region of pixel data from a larger - * source buffer */ -static void -prep_gl_for_pixels_upload_full (CoglContext *ctx, - int pixels_rowstride, - int image_height, - int pixels_src_x, - int pixels_src_y, - int pixels_bpp) -{ - GE( ctx, glPixelStorei (GL_UNPACK_ROW_LENGTH, - pixels_rowstride / pixels_bpp) ); - - GE( ctx, glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) ); - GE( ctx, glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) ); - - _cogl_texture_gl_prep_alignment_for_pixels_upload (ctx, pixels_rowstride); -} - -/* OpenGL - unlike GLES - can download pixel data into a sub region of - * a larger destination buffer */ -static void -prep_gl_for_pixels_download_full (CoglContext *ctx, - int image_width, - int pixels_rowstride, - int image_height, - int pixels_src_x, - int pixels_src_y, - int pixels_bpp) -{ - GE( ctx, glPixelStorei (GL_PACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) ); - - GE( ctx, glPixelStorei (GL_PACK_SKIP_PIXELS, pixels_src_x) ); - GE( ctx, glPixelStorei (GL_PACK_SKIP_ROWS, pixels_src_y) ); - - _cogl_texture_gl_prep_alignment_for_pixels_download (ctx, - pixels_bpp, - image_width, - pixels_rowstride); -} - -static void -_cogl_texture_driver_prep_gl_for_pixels_download (CoglContext *ctx, - int image_width, - int pixels_rowstride, - int pixels_bpp) -{ - prep_gl_for_pixels_download_full (ctx, - pixels_rowstride, - image_width, - 0 /* image height */, - 0, 0, /* pixels_src_x/y */ - pixels_bpp); -} - -static gboolean -_cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, - CoglTexture *texture, - int src_x, - int src_y, - int dst_x, - int dst_y, - int width, - int height, - int level, - CoglBitmap *source_bmp, - GLuint source_gl_format, - GLuint source_gl_type, - GError **error) -{ - GLenum gl_target; - GLuint gl_handle; - uint8_t *data; - CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); - int bpp; - gboolean status = TRUE; - GError *internal_error = NULL; - int level_width; - int level_height; - - g_return_val_if_fail (source_format != COGL_PIXEL_FORMAT_ANY, FALSE); - g_return_val_if_fail (cogl_pixel_format_get_n_planes (source_format) == 1, - FALSE); - - bpp = cogl_pixel_format_get_bytes_per_pixel (source_format, 0); - cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target); - - data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, &internal_error); - - /* NB: _cogl_bitmap_gl_bind() may return NULL when successful so we - * have to explicitly check the cogl error pointer to catch - * problems... */ - if (internal_error) - { - g_propagate_error (error, internal_error); - return FALSE; - } - - /* Setup gl alignment to match rowstride and top-left corner */ - prep_gl_for_pixels_upload_full (ctx, - cogl_bitmap_get_rowstride (source_bmp), - 0, - src_x, - src_y, - bpp); - - _cogl_bind_gl_texture_transient (gl_target, gl_handle); - - /* Clear any GL errors */ - _cogl_gl_util_clear_gl_errors (ctx); - - _cogl_texture_get_level_size (texture, - level, - &level_width, - &level_height, - NULL); - - if (level_width == width && level_height == height) - { - /* GL gets upset if you use glTexSubImage2D to initialize the - * contents of a mipmap level so we make sure to use - * glTexImage2D if we are uploading a full mipmap level. - */ - ctx->glTexImage2D (gl_target, - level, - _cogl_texture_gl_get_format (texture), - width, - height, - 0, - source_gl_format, - source_gl_type, - data); - - } - else - { - /* GL gets upset if you use glTexSubImage2D to initialize the - * contents of a mipmap level so if this is the first time - * we've seen a request to upload to this level we call - * glTexImage2D first to assert that the storage for this - * level exists. - */ - if (texture->max_level_set < level) - { - ctx->glTexImage2D (gl_target, - level, - _cogl_texture_gl_get_format (texture), - level_width, - level_height, - 0, - source_gl_format, - source_gl_type, - NULL); - } - - ctx->glTexSubImage2D (gl_target, - level, - dst_x, dst_y, - width, height, - source_gl_format, - source_gl_type, - data); - } - - if (_cogl_gl_util_catch_out_of_memory (ctx, error)) - status = FALSE; - - _cogl_bitmap_gl_unbind (source_bmp); - - return status; -} - -static gboolean -_cogl_texture_driver_upload_to_gl (CoglContext *ctx, - GLenum gl_target, - GLuint gl_handle, - CoglBitmap *source_bmp, - GLint internal_gl_format, - GLuint source_gl_format, - GLuint source_gl_type, - GError **error) -{ - uint8_t *data; - CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); - int bpp; - gboolean status = TRUE; - GError *internal_error = NULL; - - g_return_val_if_fail (source_format != COGL_PIXEL_FORMAT_ANY, FALSE); - g_return_val_if_fail (cogl_pixel_format_get_n_planes (source_format) == 1, - FALSE); - - bpp = cogl_pixel_format_get_bytes_per_pixel (source_format, 0); - - data = _cogl_bitmap_gl_bind (source_bmp, - COGL_BUFFER_ACCESS_READ, - 0, /* hints */ - &internal_error); - - /* NB: _cogl_bitmap_gl_bind() may return NULL when successful so we - * have to explicitly check the cogl error pointer to catch - * problems... */ - if (internal_error) - { - g_propagate_error (error, internal_error); - return FALSE; - } - - /* Setup gl alignment to match rowstride and top-left corner */ - prep_gl_for_pixels_upload_full (ctx, - cogl_bitmap_get_rowstride (source_bmp), - 0, 0, 0, bpp); - - _cogl_bind_gl_texture_transient (gl_target, gl_handle); - - /* Clear any GL errors */ - _cogl_gl_util_clear_gl_errors (ctx); - - ctx->glTexImage2D (gl_target, 0, - internal_gl_format, - cogl_bitmap_get_width (source_bmp), - cogl_bitmap_get_height (source_bmp), - 0, - source_gl_format, - source_gl_type, - data); - - if (_cogl_gl_util_catch_out_of_memory (ctx, error)) - status = FALSE; - - _cogl_bitmap_gl_unbind (source_bmp); - - return status; -} - -static gboolean -_cogl_texture_driver_gl_get_tex_image (CoglContext *ctx, - GLenum gl_target, - GLenum dest_gl_format, - GLenum dest_gl_type, - uint8_t *dest) -{ - GE (ctx, glGetTexImage (gl_target, - 0, /* level */ - dest_gl_format, - dest_gl_type, - (GLvoid *)dest)); - return TRUE; -} - -static gboolean -_cogl_texture_driver_size_supported (CoglContext *ctx, - GLenum gl_target, - GLenum gl_intformat, - GLenum gl_format, - GLenum gl_type, - int width, - int height) -{ - GLenum proxy_target; - GLint new_width = 0; - - if (gl_target == GL_TEXTURE_2D) - proxy_target = GL_PROXY_TEXTURE_2D; -#ifdef HAVE_COGL_GL - else if (gl_target == GL_TEXTURE_RECTANGLE_ARB) - proxy_target = GL_PROXY_TEXTURE_RECTANGLE_ARB; -#endif - else - /* Unknown target, assume it's not supported */ - return FALSE; - - /* Proxy texture allows for a quick check for supported size */ - GE( ctx, glTexImage2D (proxy_target, 0, gl_intformat, - width, height, 0 /* border */, - gl_format, gl_type, NULL) ); - - GE( ctx, glGetTexLevelParameteriv (proxy_target, 0, - GL_TEXTURE_WIDTH, &new_width) ); - - return new_width != 0; -} - -static gboolean -_cogl_texture_driver_upload_supported (CoglContext *ctx, - CoglPixelFormat format) -{ - switch (format) - { - case COGL_PIXEL_FORMAT_A_8: - case COGL_PIXEL_FORMAT_G_8: - case COGL_PIXEL_FORMAT_RG_88: - case COGL_PIXEL_FORMAT_BGRA_8888: - case COGL_PIXEL_FORMAT_BGRA_8888_PRE: - case COGL_PIXEL_FORMAT_RGB_888: - case COGL_PIXEL_FORMAT_BGR_888: - case COGL_PIXEL_FORMAT_RGBA_1010102: - case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: - case COGL_PIXEL_FORMAT_BGRA_1010102: - case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: - case COGL_PIXEL_FORMAT_ABGR_2101010: - case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: - case COGL_PIXEL_FORMAT_ARGB_2101010: - case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: - case COGL_PIXEL_FORMAT_RGBA_8888: - case COGL_PIXEL_FORMAT_RGBA_8888_PRE: - case COGL_PIXEL_FORMAT_ARGB_8888: - case COGL_PIXEL_FORMAT_ARGB_8888_PRE: - case COGL_PIXEL_FORMAT_ABGR_8888: - case COGL_PIXEL_FORMAT_ABGR_8888_PRE: - case COGL_PIXEL_FORMAT_RGB_565: - case COGL_PIXEL_FORMAT_RGBA_4444: - case COGL_PIXEL_FORMAT_RGBA_4444_PRE: - case COGL_PIXEL_FORMAT_RGBA_5551: - case COGL_PIXEL_FORMAT_RGBA_5551_PRE: - return TRUE; - case COGL_PIXEL_FORMAT_BGRA_FP_16161616: - case COGL_PIXEL_FORMAT_ARGB_FP_16161616: - case COGL_PIXEL_FORMAT_ABGR_FP_16161616: - case COGL_PIXEL_FORMAT_BGRA_FP_16161616_PRE: - case COGL_PIXEL_FORMAT_ARGB_FP_16161616_PRE: - case COGL_PIXEL_FORMAT_ABGR_FP_16161616_PRE: - case COGL_PIXEL_FORMAT_RGBA_FP_16161616: - case COGL_PIXEL_FORMAT_RGBA_FP_16161616_PRE: - if (_cogl_has_private_feature - (ctx, COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_HALF_FLOAT)) - return TRUE; - else - return FALSE; - case COGL_PIXEL_FORMAT_DEPTH_16: - case COGL_PIXEL_FORMAT_DEPTH_32: - case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8: - case COGL_PIXEL_FORMAT_ANY: - case COGL_PIXEL_FORMAT_YUV: - return TRUE; - } - - g_assert_not_reached (); - return FALSE; -} - -static CoglPixelFormat -_cogl_texture_driver_find_best_gl_get_data_format - (CoglContext *context, - CoglPixelFormat format, - GLenum *closest_gl_format, - GLenum *closest_gl_type) -{ - return context->driver_vtable->pixel_format_to_gl (context, - format, - NULL, /* don't need */ - closest_gl_format, - closest_gl_type); -} - -const CoglTextureDriver -_cogl_texture_driver_gl = - { - _cogl_texture_driver_gen, - _cogl_texture_driver_upload_subregion_to_gl, - _cogl_texture_driver_upload_to_gl, - _cogl_texture_driver_prep_gl_for_pixels_download, - _cogl_texture_driver_gl_get_tex_image, - _cogl_texture_driver_size_supported, - _cogl_texture_driver_upload_supported, - _cogl_texture_driver_find_best_gl_get_data_format - }; diff --git a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c deleted file mode 100644 index 633e2c415..000000000 --- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2007,2008,2009 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - */ - -#include "cogl-config.h" - -#include <string.h> - -#include "cogl-context-private.h" -#include "cogl-feature-private.h" -#include "cogl-renderer-private.h" -#include "cogl-private.h" -#include "driver/gl/cogl-util-gl-private.h" -#include "driver/gl/cogl-framebuffer-gl-private.h" -#include "driver/gl/cogl-texture-2d-gl-private.h" -#include "driver/gl/cogl-attribute-gl-private.h" -#include "driver/gl/cogl-clip-stack-gl-private.h" -#include "driver/gl/cogl-buffer-gl-private.h" -#include "driver/gl/cogl-pipeline-opengl-private.h" - -#ifndef GL_UNSIGNED_INT_24_8 -#define GL_UNSIGNED_INT_24_8 0x84FA -#endif -#ifndef GL_DEPTH_STENCIL -#define GL_DEPTH_STENCIL 0x84F9 -#endif -#ifndef GL_RG -#define GL_RG 0x8227 -#endif -#ifndef GL_RG8 -#define GL_RG8 0x822B -#endif -#ifndef GL_UNSIGNED_INT_2_10_10_10_REV_EXT -#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368 -#endif -#ifndef GL_HALF_FLOAT_OES -#define GL_HALF_FLOAT_OES 0x8D61 -#endif - -static gboolean -_cogl_driver_pixel_format_from_gl_internal (CoglContext *context, - GLenum gl_int_format, - CoglPixelFormat *out_format) -{ - return TRUE; -} - -static CoglPixelFormat -_cogl_driver_pixel_format_to_gl (CoglContext *context, - CoglPixelFormat format, - GLenum *out_glintformat, - GLenum *out_glformat, - GLenum *out_gltype) -{ - CoglPixelFormat required_format; - GLenum glintformat; - GLenum glformat = 0; - GLenum gltype; - - required_format = format; - - /* Find GL equivalents */ - switch (format) - { - case COGL_PIXEL_FORMAT_A_8: - glintformat = GL_ALPHA; - glformat = GL_ALPHA; - gltype = GL_UNSIGNED_BYTE; - break; - case COGL_PIXEL_FORMAT_G_8: - glintformat = GL_LUMINANCE; - glformat = GL_LUMINANCE; - gltype = GL_UNSIGNED_BYTE; - break; - - case COGL_PIXEL_FORMAT_RG_88: - if (cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_RG)) - { - glintformat = GL_RG8; - glformat = GL_RG; - } - else - { - /* If red-green textures aren't supported then we'll use RGB - * as an internal format. Note this should only end up - * mattering for downloading the data because Cogl will - * refuse to allocate a texture with RG components if RG - * textures aren't supported */ - glintformat = GL_RGB; - glformat = GL_RGB; - required_format = COGL_PIXEL_FORMAT_RGB_888; - } - gltype = GL_UNSIGNED_BYTE; - break; - - case COGL_PIXEL_FORMAT_BGRA_8888: - case COGL_PIXEL_FORMAT_BGRA_8888_PRE: - /* There is an extension to support this format */ - if (_cogl_has_private_feature - (context, COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_BGRA8888)) - { - /* For some reason the extension says you have to specify - BGRA for the internal format too */ - glintformat = GL_BGRA_EXT; - glformat = GL_BGRA_EXT; - gltype = GL_UNSIGNED_BYTE; - required_format = format; - break; - } - /* flow through */ - - /* Just one 24-bit ordering supported */ - case COGL_PIXEL_FORMAT_RGB_888: - case COGL_PIXEL_FORMAT_BGR_888: - glintformat = GL_RGB; - glformat = GL_RGB; - gltype = GL_UNSIGNED_BYTE; - required_format = COGL_PIXEL_FORMAT_RGB_888; - break; - - case COGL_PIXEL_FORMAT_RGBA_1010102: - case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - if (_cogl_has_private_feature - (context, COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_RGBA1010102)) - { - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_INT_2_10_10_10_REV_EXT; - break; - } -#endif - case COGL_PIXEL_FORMAT_BGRA_1010102: - case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: - case COGL_PIXEL_FORMAT_ABGR_2101010: - case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: - case COGL_PIXEL_FORMAT_ARGB_2101010: - case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - if (_cogl_has_private_feature - (context, COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_RGBA1010102)) - { - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_INT_2_10_10_10_REV_EXT; - required_format = COGL_PIXEL_FORMAT_RGBA_1010102; - required_format |= (format & COGL_PREMULT_BIT); - break; - } -#endif - - G_GNUC_FALLTHROUGH; - case COGL_PIXEL_FORMAT_RGBA_8888: - case COGL_PIXEL_FORMAT_RGBA_8888_PRE: - case COGL_PIXEL_FORMAT_ARGB_8888: - case COGL_PIXEL_FORMAT_ARGB_8888_PRE: - case COGL_PIXEL_FORMAT_ABGR_8888: - case COGL_PIXEL_FORMAT_ABGR_8888_PRE: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_BYTE; - required_format = COGL_PIXEL_FORMAT_RGBA_8888; - required_format |= (format & COGL_PREMULT_BIT); - break; - - /* The following three types of channel ordering - * are always defined using system word byte - * ordering (even according to GLES spec) */ - case COGL_PIXEL_FORMAT_RGB_565: - glintformat = GL_RGB; - glformat = GL_RGB; - gltype = GL_UNSIGNED_SHORT_5_6_5; - break; - case COGL_PIXEL_FORMAT_RGBA_4444: - case COGL_PIXEL_FORMAT_RGBA_4444_PRE: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_SHORT_4_4_4_4; - break; - case COGL_PIXEL_FORMAT_RGBA_5551: - case COGL_PIXEL_FORMAT_RGBA_5551_PRE: - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_UNSIGNED_SHORT_5_5_5_1; - break; - - case COGL_PIXEL_FORMAT_BGRA_FP_16161616: - case COGL_PIXEL_FORMAT_ARGB_FP_16161616: - case COGL_PIXEL_FORMAT_ABGR_FP_16161616: - case COGL_PIXEL_FORMAT_BGRA_FP_16161616_PRE: - case COGL_PIXEL_FORMAT_ARGB_FP_16161616_PRE: - case COGL_PIXEL_FORMAT_ABGR_FP_16161616_PRE: - g_warning ("Unhandled 16 bpc pixel format used"); - - G_GNUC_FALLTHROUGH; - case COGL_PIXEL_FORMAT_RGBA_FP_16161616: - case COGL_PIXEL_FORMAT_RGBA_FP_16161616_PRE: - if (!_cogl_has_private_feature - (context, COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_HALF_FLOAT)) - g_warning ("Missing 16 bpc half float extension"); - - glintformat = GL_RGBA; - glformat = GL_RGBA; - gltype = GL_HALF_FLOAT_OES; - break; - - case COGL_PIXEL_FORMAT_DEPTH_16: - glintformat = GL_DEPTH_COMPONENT; - glformat = GL_DEPTH_COMPONENT; - gltype = GL_UNSIGNED_SHORT; - break; - case COGL_PIXEL_FORMAT_DEPTH_32: - glintformat = GL_DEPTH_COMPONENT; - glformat = GL_DEPTH_COMPONENT; - gltype = GL_UNSIGNED_INT; - break; - - case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8: - glintformat = GL_DEPTH_STENCIL; - glformat = GL_DEPTH_STENCIL; - gltype = GL_UNSIGNED_INT_24_8; - break; - - case COGL_PIXEL_FORMAT_ANY: - case COGL_PIXEL_FORMAT_YUV: - g_assert_not_reached (); - break; - } - - /* All of the pixel formats are handled above so if this hits then - we've been given an invalid pixel format */ - g_assert (glformat != 0); - - if (out_glintformat != NULL) - *out_glintformat = glintformat; - if (out_glformat != NULL) - *out_glformat = glformat; - if (out_gltype != NULL) - *out_gltype = gltype; - - return required_format; -} - -static gboolean -_cogl_get_gl_version (CoglContext *ctx, - int *major_out, - int *minor_out) -{ - const char *version_string; - - /* Get the OpenGL version number */ - if ((version_string = _cogl_context_get_gl_version (ctx)) == NULL) - return FALSE; - - if (!g_str_has_prefix (version_string, "OpenGL ES ")) - return FALSE; - - return _cogl_gl_util_parse_gl_version (version_string + 10, - major_out, - minor_out); -} - -static gboolean -_cogl_driver_update_features (CoglContext *context, - GError **error) -{ - unsigned long private_features - [COGL_FLAGS_N_LONGS_FOR_SIZE (COGL_N_PRIVATE_FEATURES)] = { 0 }; - char **gl_extensions; - int gl_major, gl_minor; - int i; - - /* We have to special case getting the pointer to the glGetString - function because we need to use it to determine what functions we - can expect */ - context->glGetString = - (void *) _cogl_renderer_get_proc_address (context->display->renderer, - "glGetString", - TRUE); - context->glGetStringi = - (void *) _cogl_renderer_get_proc_address (context->display->renderer, - "glGetStringi", - TRUE); - - gl_extensions = _cogl_context_get_gl_extensions (context); - - if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WINSYS))) - { - char *all_extensions = g_strjoinv (" ", gl_extensions); - - COGL_NOTE (WINSYS, - "Checking features\n" - " GL_VENDOR: %s\n" - " GL_RENDERER: %s\n" - " GL_VERSION: %s\n" - " GL_EXTENSIONS: %s", - context->glGetString (GL_VENDOR), - context->glGetString (GL_RENDERER), - _cogl_context_get_gl_version (context), - all_extensions); - - g_free (all_extensions); - } - - context->glsl_major = 1; - context->glsl_minor = 0; - context->glsl_version_to_use = 100; - - if (!_cogl_get_gl_version (context, &gl_major, &gl_minor)) - { - gl_major = 1; - gl_minor = 1; - } - - if (!COGL_CHECK_GL_VERSION (gl_major, gl_minor, 2, 0)) - { - g_set_error (error, - COGL_DRIVER_ERROR, - COGL_DRIVER_ERROR_INVALID_VERSION, - "OpenGL ES 2.0 or better is required"); - return FALSE; - } - - _cogl_feature_check_ext_functions (context, - gl_major, - gl_minor, - gl_extensions); - - if (_cogl_check_extension ("GL_ANGLE_pack_reverse_row_order", gl_extensions)) - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_MESA_PACK_INVERT, TRUE); - - /* Note GLES 2 core doesn't support mipmaps for npot textures or - * repeat modes other than CLAMP_TO_EDGE. */ - - COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_ANY_GL, TRUE); - COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES, TRUE); - - if (context->glGenSamplers) - COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS, TRUE); - - if (context->glBlitFramebuffer) - COGL_FLAGS_SET (context->features, - COGL_FEATURE_ID_BLIT_FRAMEBUFFER, TRUE); - - if (_cogl_check_extension ("GL_OES_element_index_uint", gl_extensions)) - { - COGL_FLAGS_SET (context->features, - COGL_FEATURE_ID_UNSIGNED_INT_INDICES, TRUE); - } - - if (context->glMapBuffer) - { - /* The GL_OES_mapbuffer extension doesn't support mapping for - read */ - COGL_FLAGS_SET (context->features, - COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, TRUE); - } - - if (context->glMapBufferRange) - { - /* MapBufferRange in ES3+ does support mapping for read */ - COGL_FLAGS_SET(context->features, - COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE, TRUE); - COGL_FLAGS_SET(context->features, - COGL_FEATURE_ID_MAP_BUFFER_FOR_READ, TRUE); - } - - if (context->glEGLImageTargetTexture2D) - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE, TRUE); - - if (_cogl_check_extension ("GL_OES_packed_depth_stencil", gl_extensions)) - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL, TRUE); - - if (_cogl_check_extension ("GL_EXT_texture_format_BGRA8888", gl_extensions)) - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_BGRA8888, TRUE); - - if (_cogl_check_extension ("GL_EXT_texture_type_2_10_10_10_REV", gl_extensions)) - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_RGBA1010102, TRUE); - - if (_cogl_check_extension ("GL_OES_texture_half_float", gl_extensions)) - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_HALF_FLOAT, TRUE); - - if (_cogl_check_extension ("GL_EXT_unpack_subimage", gl_extensions)) - COGL_FLAGS_SET (private_features, - COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE, TRUE); - - /* A nameless vendor implemented the extension, but got the case wrong - * per the spec. */ - if (_cogl_check_extension ("GL_OES_EGL_sync", gl_extensions) || - _cogl_check_extension ("GL_OES_egl_sync", gl_extensions)) - COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_OES_EGL_SYNC, TRUE); - -#ifdef GL_ARB_sync - if (context->glFenceSync) - COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_FENCE, TRUE); -#endif - - if (_cogl_check_extension ("GL_EXT_texture_rg", gl_extensions)) - COGL_FLAGS_SET (context->features, - COGL_FEATURE_ID_TEXTURE_RG, - TRUE); - - if (context->glGenQueries && context->glQueryCounter) - COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TIMESTAMP_QUERY, TRUE); - - if (context->glGetInteger64v) - COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_GET_GPU_TIME, TRUE); - - /* Cache features */ - for (i = 0; i < G_N_ELEMENTS (private_features); i++) - context->private_features[i] |= private_features[i]; - - g_strfreev (gl_extensions); - - return TRUE; -} - -static gboolean -_cogl_driver_texture_2d_is_get_data_supported (CoglTexture2D *tex_2d) -{ - return FALSE; -} - -const CoglDriverVtable -_cogl_driver_gles = - { - _cogl_driver_gl_context_init, - _cogl_driver_gl_context_deinit, - _cogl_driver_gl_is_hardware_accelerated, - _cogl_gl_get_graphics_reset_status, - _cogl_driver_pixel_format_from_gl_internal, - _cogl_driver_pixel_format_to_gl, - _cogl_driver_update_features, - _cogl_driver_gl_create_framebuffer_driver, - _cogl_driver_gl_flush_framebuffer_state, - _cogl_texture_2d_gl_free, - _cogl_texture_2d_gl_can_create, - _cogl_texture_2d_gl_init, - _cogl_texture_2d_gl_allocate, - _cogl_texture_2d_gl_copy_from_framebuffer, - _cogl_texture_2d_gl_get_gl_handle, - _cogl_texture_2d_gl_generate_mipmap, - _cogl_texture_2d_gl_copy_from_bitmap, - _cogl_driver_texture_2d_is_get_data_supported, - NULL, /* texture_2d_get_data */ - _cogl_gl_flush_attributes_state, - _cogl_clip_stack_gl_flush, - _cogl_buffer_gl_create, - _cogl_buffer_gl_destroy, - _cogl_buffer_gl_map_range, - _cogl_buffer_gl_unmap, - _cogl_buffer_gl_set_data, - _cogl_sampler_gl_init, - _cogl_sampler_gl_free, - _cogl_gl_set_uniform, - cogl_gl_create_timestamp_query, - cogl_gl_free_timestamp_query, - cogl_gl_timestamp_query_get_time_ns, - cogl_gl_get_gpu_time_ns, - }; diff --git a/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c deleted file mode 100644 index 904d39d34..000000000 --- a/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c +++ /dev/null @@ -1,537 +0,0 @@ -/* - * Cogl - * - * A Low Level GPU Graphics and Utilities API - * - * Copyright (C) 2007,2008,2009 Intel Corporation. - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * - * - * Authors: - * Matthew Allum <mallum@openedhand.com> - * Neil Roberts <neil@linux.intel.com> - * Robert Bragg <robert@linux.intel.com> - */ - -#include "cogl-config.h" - -#include "cogl-private.h" -#include "cogl-util.h" -#include "cogl-bitmap.h" -#include "cogl-bitmap-private.h" -#include "cogl-texture-private.h" -#include "cogl-pipeline.h" -#include "cogl-context-private.h" -#include "cogl-object-private.h" -#include "driver/gl/cogl-pipeline-opengl-private.h" -#include "driver/gl/cogl-util-gl-private.h" -#include "driver/gl/cogl-texture-gl-private.h" -#include "driver/gl/cogl-bitmap-gl-private.h" - -#include <string.h> -#include <stdlib.h> -#include <math.h> - -#ifndef GL_TEXTURE_3D -#define GL_TEXTURE_3D 0x806F -#endif -#ifndef GL_MAX_3D_TEXTURE_SIZE_OES -#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073 -#endif - -/* This extension isn't available for GLES 1.1 so these won't be - defined */ -#ifndef GL_UNPACK_ROW_LENGTH -#define GL_UNPACK_ROW_LENGTH 0x0CF2 -#endif -#ifndef GL_UNPACK_SKIP_ROWS -#define GL_UNPACK_SKIP_ROWS 0x0CF3 -#endif -#ifndef GL_UNPACK_SKIP_PIXELS -#define GL_UNPACK_SKIP_PIXELS 0x0CF4 -#endif - -static GLuint -_cogl_texture_driver_gen (CoglContext *ctx, - GLenum gl_target, - CoglPixelFormat internal_format) -{ - GLuint tex; - - GE (ctx, glGenTextures (1, &tex)); - - _cogl_bind_gl_texture_transient (gl_target, tex); - - switch (gl_target) - { - case GL_TEXTURE_2D: - case GL_TEXTURE_3D: - /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */ - GE( ctx, glTexParameteri (gl_target, - GL_TEXTURE_MIN_FILTER, - GL_LINEAR) ); - break; - - default: - g_assert_not_reached(); - } - - return tex; -} - -static void -prep_gl_for_pixels_upload_full (CoglContext *ctx, - int pixels_rowstride, - int pixels_src_x, - int pixels_src_y, - int pixels_bpp) -{ - if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE)) - { - GE( ctx, glPixelStorei (GL_UNPACK_ROW_LENGTH, - pixels_rowstride / pixels_bpp) ); - - GE( ctx, glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) ); - GE( ctx, glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) ); - } - else - { - g_assert (pixels_src_x == 0); - g_assert (pixels_src_y == 0); - } - - _cogl_texture_gl_prep_alignment_for_pixels_upload (ctx, pixels_rowstride); -} - -static void -_cogl_texture_driver_prep_gl_for_pixels_upload (CoglContext *ctx, - int pixels_rowstride, - int pixels_bpp) -{ - prep_gl_for_pixels_upload_full (ctx, - pixels_rowstride, - 0, 0, /* src_x/y */ - pixels_bpp); -} - -static void -_cogl_texture_driver_prep_gl_for_pixels_download (CoglContext *ctx, - int pixels_rowstride, - int image_width, - int pixels_bpp) -{ - _cogl_texture_gl_prep_alignment_for_pixels_download (ctx, - pixels_bpp, - image_width, - pixels_rowstride); -} - -static CoglBitmap * -prepare_bitmap_alignment_for_upload (CoglContext *ctx, - CoglBitmap *src_bmp, - GError **error) -{ - CoglPixelFormat format = cogl_bitmap_get_format (src_bmp); - int bpp; - int src_rowstride = cogl_bitmap_get_rowstride (src_bmp); - int width = cogl_bitmap_get_width (src_bmp); - int alignment = 1; - - g_return_val_if_fail (format != COGL_PIXEL_FORMAT_ANY, FALSE); - g_return_val_if_fail (cogl_pixel_format_get_n_planes (format) == 1, FALSE); - - bpp = cogl_pixel_format_get_bytes_per_pixel (format, 0); - - if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE) || - src_rowstride == 0) - return cogl_object_ref (src_bmp); - - /* Work out the alignment of the source rowstride */ - alignment = 1 << (ffs (src_rowstride) - 1); - alignment = MIN (alignment, 8); - - /* If the aligned data equals the rowstride then we can upload from - the bitmap directly using GL_UNPACK_ALIGNMENT */ - if (((width * bpp + alignment - 1) & ~(alignment - 1)) == src_rowstride) - return cogl_object_ref (src_bmp); - /* Otherwise we need to copy the bitmap to pack the alignment - because GLES has no GL_ROW_LENGTH */ - else - return _cogl_bitmap_copy (src_bmp, error); -} - -static gboolean -_cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx, - CoglTexture *texture, - int src_x, - int src_y, - int dst_x, - int dst_y, - int width, - int height, - int level, - CoglBitmap *source_bmp, - GLuint source_gl_format, - GLuint source_gl_type, - GError **error) -{ - GLenum gl_target; - GLuint gl_handle; - uint8_t *data; - CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); - int bpp; - CoglBitmap *slice_bmp; - int rowstride; - gboolean status = TRUE; - GError *internal_error = NULL; - int level_width; - int level_height; - - g_return_val_if_fail (source_format != COGL_PIXEL_FORMAT_ANY, FALSE); - g_return_val_if_fail (cogl_pixel_format_get_n_planes (source_format) == 1, - FALSE); - - bpp = cogl_pixel_format_get_bytes_per_pixel (source_format, 0); - - cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target); - - /* If we have the GL_EXT_unpack_subimage extension then we can - upload from subregions directly. Otherwise we may need to copy - the bitmap */ - if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_UNPACK_SUBIMAGE) && - (src_x != 0 || src_y != 0 || - width != cogl_bitmap_get_width (source_bmp) || - height != cogl_bitmap_get_height (source_bmp))) - { - slice_bmp = - _cogl_bitmap_new_with_malloc_buffer (ctx, - width, height, - source_format, - error); - if (!slice_bmp) - return FALSE; - - if (!_cogl_bitmap_copy_subregion (source_bmp, - slice_bmp, - src_x, src_y, - 0, 0, /* dst_x/y */ - width, height, - error)) - { - cogl_object_unref (slice_bmp); - return FALSE; - } - - src_x = src_y = 0; - } - else - { - slice_bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp, error); - if (!slice_bmp) - return FALSE; - } - - rowstride = cogl_bitmap_get_rowstride (slice_bmp); - - /* Setup gl alignment to match rowstride and top-left corner */ - prep_gl_for_pixels_upload_full (ctx, rowstride, src_x, src_y, bpp); - - data = _cogl_bitmap_gl_bind (slice_bmp, COGL_BUFFER_ACCESS_READ, 0, &internal_error); - - /* NB: _cogl_bitmap_gl_bind() may return NULL when successful so we - * have to explicitly check the cogl error pointer to catch - * problems... */ - if (internal_error) - { - g_propagate_error (error, internal_error); - cogl_object_unref (slice_bmp); - return FALSE; - } - - _cogl_bind_gl_texture_transient (gl_target, gl_handle); - - /* Clear any GL errors */ - _cogl_gl_util_clear_gl_errors (ctx); - - _cogl_texture_get_level_size (texture, - level, - &level_width, - &level_height, - NULL); - - if (level_width == width && level_height == height) - { - /* GL gets upset if you use glTexSubImage2D to define the - * contents of a mipmap level so we make sure to use - * glTexImage2D if we are uploading a full mipmap level. - */ - ctx->glTexImage2D (gl_target, - level, - _cogl_texture_gl_get_format (texture), - width, - height, - 0, - source_gl_format, - source_gl_type, - data); - } - else - { - /* GL gets upset if you use glTexSubImage2D to initialize the - * contents of a mipmap level so if this is the first time - * we've seen a request to upload to this level we call - * glTexImage2D first to assert that the storage for this - * level exists. - */ - if (texture->max_level_set < level) - { - ctx->glTexImage2D (gl_target, - level, - _cogl_texture_gl_get_format (texture), - level_width, - level_height, - 0, - source_gl_format, - source_gl_type, - NULL); - } - - ctx->glTexSubImage2D (gl_target, - level, - dst_x, dst_y, - width, height, - source_gl_format, - source_gl_type, - data); - } - - if (_cogl_gl_util_catch_out_of_memory (ctx, error)) - status = FALSE; - - _cogl_bitmap_gl_unbind (slice_bmp); - - cogl_object_unref (slice_bmp); - - return status; -} - -static gboolean -_cogl_texture_driver_upload_to_gl (CoglContext *ctx, - GLenum gl_target, - GLuint gl_handle, - CoglBitmap *source_bmp, - GLint internal_gl_format, - GLuint source_gl_format, - GLuint source_gl_type, - GError **error) -{ - CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp); - int bpp; - int rowstride; - int bmp_width = cogl_bitmap_get_width (source_bmp); - int bmp_height = cogl_bitmap_get_height (source_bmp); - CoglBitmap *bmp; - uint8_t *data; - GError *internal_error = NULL; - gboolean status = TRUE; - - g_return_val_if_fail (source_format != COGL_PIXEL_FORMAT_ANY, FALSE); - g_return_val_if_fail (cogl_pixel_format_get_n_planes (source_format) == 1, - FALSE); - - bpp = cogl_pixel_format_get_bytes_per_pixel (source_format, 0); - - bmp = prepare_bitmap_alignment_for_upload (ctx, source_bmp, error); - if (!bmp) - return FALSE; - - rowstride = cogl_bitmap_get_rowstride (bmp); - - /* Setup gl alignment to match rowstride and top-left corner */ - _cogl_texture_driver_prep_gl_for_pixels_upload (ctx, rowstride, bpp); - - _cogl_bind_gl_texture_transient (gl_target, gl_handle); - - data = _cogl_bitmap_gl_bind (bmp, - COGL_BUFFER_ACCESS_READ, - 0, /* hints */ - &internal_error); - - /* NB: _cogl_bitmap_gl_bind() may return NULL when successful so we - * have to explicitly check the cogl error pointer to catch - * problems... */ - if (internal_error) - { - cogl_object_unref (bmp); - g_propagate_error (error, internal_error); - return FALSE; - } - - /* Clear any GL errors */ - _cogl_gl_util_clear_gl_errors (ctx); - - ctx->glTexImage2D (gl_target, 0, - internal_gl_format, - bmp_width, bmp_height, - 0, - source_gl_format, - source_gl_type, - data); - - if (_cogl_gl_util_catch_out_of_memory (ctx, error)) - status = FALSE; - - _cogl_bitmap_gl_unbind (bmp); - - cogl_object_unref (bmp); - - return status; -} - -/* NB: GLES doesn't support glGetTexImage2D, so cogl-texture will instead - * fallback to a generic render + readpixels approach to downloading - * texture data. (See _cogl_texture_draw_and_read() ) */ -static gboolean -_cogl_texture_driver_gl_get_tex_image (CoglContext *ctx, - GLenum gl_target, - GLenum dest_gl_format, - GLenum dest_gl_type, - uint8_t *dest) -{ - return FALSE; -} - -static gboolean -_cogl_texture_driver_size_supported (CoglContext *ctx, - GLenum gl_target, - GLenum gl_intformat, - GLenum gl_format, - GLenum gl_type, - int width, - int height) -{ - GLint max_size; - - /* GLES doesn't support a proxy texture target so let's at least - check whether the size is greater than GL_MAX_TEXTURE_SIZE */ - GE( ctx, glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_size) ); - - return width <= max_size && height <= max_size; -} - -static gboolean -_cogl_texture_driver_upload_supported (CoglContext *ctx, - CoglPixelFormat format) -{ - switch (format) - { - case COGL_PIXEL_FORMAT_A_8: - case COGL_PIXEL_FORMAT_G_8: - case COGL_PIXEL_FORMAT_RG_88: - case COGL_PIXEL_FORMAT_BGRA_8888: - case COGL_PIXEL_FORMAT_BGRA_8888_PRE: - case COGL_PIXEL_FORMAT_RGB_888: - case COGL_PIXEL_FORMAT_BGR_888: - return TRUE; - case COGL_PIXEL_FORMAT_RGBA_1010102: - case COGL_PIXEL_FORMAT_RGBA_1010102_PRE: - case COGL_PIXEL_FORMAT_BGRA_1010102: - case COGL_PIXEL_FORMAT_BGRA_1010102_PRE: - case COGL_PIXEL_FORMAT_ABGR_2101010: - case COGL_PIXEL_FORMAT_ABGR_2101010_PRE: - case COGL_PIXEL_FORMAT_ARGB_2101010: - case COGL_PIXEL_FORMAT_ARGB_2101010_PRE: -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - if (_cogl_has_private_feature - (ctx, COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_RGBA1010102)) - return TRUE; - else - return FALSE; -#else - return FALSE; -#endif - case COGL_PIXEL_FORMAT_RGBA_8888: - case COGL_PIXEL_FORMAT_RGBA_8888_PRE: - case COGL_PIXEL_FORMAT_ARGB_8888: - case COGL_PIXEL_FORMAT_ARGB_8888_PRE: - case COGL_PIXEL_FORMAT_ABGR_8888: - case COGL_PIXEL_FORMAT_ABGR_8888_PRE: - case COGL_PIXEL_FORMAT_RGB_565: - case COGL_PIXEL_FORMAT_RGBA_4444: - case COGL_PIXEL_FORMAT_RGBA_4444_PRE: - case COGL_PIXEL_FORMAT_RGBA_5551: - case COGL_PIXEL_FORMAT_RGBA_5551_PRE: - return TRUE; - case COGL_PIXEL_FORMAT_BGRA_FP_16161616: - case COGL_PIXEL_FORMAT_ARGB_FP_16161616: - case COGL_PIXEL_FORMAT_ABGR_FP_16161616: - case COGL_PIXEL_FORMAT_BGRA_FP_16161616_PRE: - case COGL_PIXEL_FORMAT_ARGB_FP_16161616_PRE: - case COGL_PIXEL_FORMAT_ABGR_FP_16161616_PRE: - return FALSE; - case COGL_PIXEL_FORMAT_RGBA_FP_16161616: - case COGL_PIXEL_FORMAT_RGBA_FP_16161616_PRE: - if (_cogl_has_private_feature - (ctx, COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_HALF_FLOAT)) - return TRUE; - else - return FALSE; - case COGL_PIXEL_FORMAT_DEPTH_16: - case COGL_PIXEL_FORMAT_DEPTH_32: - case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8: - case COGL_PIXEL_FORMAT_ANY: - case COGL_PIXEL_FORMAT_YUV: - return TRUE; - } - - g_assert_not_reached (); - return FALSE; -} - -static CoglPixelFormat -_cogl_texture_driver_find_best_gl_get_data_format - (CoglContext *context, - CoglPixelFormat format, - GLenum *closest_gl_format, - GLenum *closest_gl_type) -{ - /* Find closest format that's supported by GL - (Can't use _cogl_pixel_format_to_gl since available formats - when reading pixels on GLES are severely limited) */ - *closest_gl_format = GL_RGBA; - *closest_gl_type = GL_UNSIGNED_BYTE; - return COGL_PIXEL_FORMAT_RGBA_8888; -} - -const CoglTextureDriver -_cogl_texture_driver_gles = - { - _cogl_texture_driver_gen, - _cogl_texture_driver_upload_subregion_to_gl, - _cogl_texture_driver_upload_to_gl, - _cogl_texture_driver_prep_gl_for_pixels_download, - _cogl_texture_driver_gl_get_tex_image, - _cogl_texture_driver_size_supported, - _cogl_texture_driver_upload_supported, - _cogl_texture_driver_find_best_gl_get_data_format - }; |