mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 19:42:05 +00:00
buffer: splits out GL specific code
As part of an on-going effort to be able to support non-opengl drivers for Cogl this splits out the opengl specific code from cogl-buffer.c into driver/gl/cogl-buffer-gl.c Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit 4d7094a979ff2cbbe4054f4a44ca05fc41a9e447)
This commit is contained in:
parent
bcf6a61d0b
commit
b1ecfbf720
@ -167,6 +167,8 @@ cogl_driver_sources += \
|
|||||||
$(srcdir)/driver/gl/cogl-attribute-gl.c \
|
$(srcdir)/driver/gl/cogl-attribute-gl.c \
|
||||||
$(srcdir)/driver/gl/cogl-clip-stack-gl-private.h \
|
$(srcdir)/driver/gl/cogl-clip-stack-gl-private.h \
|
||||||
$(srcdir)/driver/gl/cogl-clip-stack-gl.c \
|
$(srcdir)/driver/gl/cogl-clip-stack-gl.c \
|
||||||
|
$(srcdir)/driver/gl/cogl-buffer-gl-private.h \
|
||||||
|
$(srcdir)/driver/gl/cogl-buffer-gl.c \
|
||||||
$(srcdir)/driver/gl/cogl-pipeline-opengl.c \
|
$(srcdir)/driver/gl/cogl-pipeline-opengl.c \
|
||||||
$(srcdir)/driver/gl/cogl-pipeline-opengl-private.h \
|
$(srcdir)/driver/gl/cogl-pipeline-opengl-private.h \
|
||||||
$(srcdir)/driver/gl/cogl-pipeline-fragend-glsl.c \
|
$(srcdir)/driver/gl/cogl-pipeline-fragend-glsl.c \
|
||||||
|
@ -384,6 +384,7 @@ _cogl_flush_attributes_state (CoglFramebuffer *framebuffer,
|
|||||||
{
|
{
|
||||||
CoglContext *ctx = framebuffer->context;
|
CoglContext *ctx = framebuffer->context;
|
||||||
CoglFlushLayerState layers_state;
|
CoglFlushLayerState layers_state;
|
||||||
|
CoglPipeline *copy = NULL;
|
||||||
|
|
||||||
if (!(flags & COGL_DRAW_SKIP_JOURNAL_FLUSH))
|
if (!(flags & COGL_DRAW_SKIP_JOURNAL_FLUSH))
|
||||||
_cogl_journal_flush (framebuffer->journal);
|
_cogl_journal_flush (framebuffer->journal);
|
||||||
@ -418,12 +419,8 @@ _cogl_flush_attributes_state (CoglFramebuffer *framebuffer,
|
|||||||
G_UNLIKELY (ctx->legacy_state_set) &&
|
G_UNLIKELY (ctx->legacy_state_set) &&
|
||||||
_cogl_get_enable_legacy_state ())
|
_cogl_get_enable_legacy_state ())
|
||||||
{
|
{
|
||||||
/* If we haven't already created a derived pipeline... */
|
copy = cogl_pipeline_copy (pipeline);
|
||||||
if (!copy)
|
pipeline = copy;
|
||||||
{
|
|
||||||
copy = cogl_pipeline_copy (pipeline);
|
|
||||||
pipeline = copy;
|
|
||||||
}
|
|
||||||
_cogl_pipeline_apply_legacy_state (pipeline);
|
_cogl_pipeline_apply_legacy_state (pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "cogl-buffer-private.h"
|
#include "cogl-buffer-private.h"
|
||||||
#include "cogl-pixel-buffer.h"
|
#include "cogl-pixel-buffer.h"
|
||||||
#include "cogl-context-private.h"
|
#include "cogl-context-private.h"
|
||||||
|
#include "cogl-buffer-gl-private.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -123,15 +123,6 @@ _cogl_buffer_initialize (CoglBuffer *buffer,
|
|||||||
void
|
void
|
||||||
_cogl_buffer_fini (CoglBuffer *buffer);
|
_cogl_buffer_fini (CoglBuffer *buffer);
|
||||||
|
|
||||||
/* TODO: split these GL specific bind and unbind functions out into
|
|
||||||
* some GL specific file. */
|
|
||||||
void *
|
|
||||||
_cogl_buffer_gl_bind (CoglBuffer *buffer,
|
|
||||||
CoglBufferBindTarget target);
|
|
||||||
|
|
||||||
void
|
|
||||||
_cogl_buffer_gl_unbind (CoglBuffer *buffer);
|
|
||||||
|
|
||||||
CoglBufferUsageHint
|
CoglBufferUsageHint
|
||||||
_cogl_buffer_get_usage_hint (CoglBuffer *buffer);
|
_cogl_buffer_get_usage_hint (CoglBuffer *buffer);
|
||||||
|
|
||||||
|
@ -44,32 +44,6 @@
|
|||||||
#include "cogl-object-private.h"
|
#include "cogl-object-private.h"
|
||||||
#include "cogl-pixel-buffer-private.h"
|
#include "cogl-pixel-buffer-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
|
|
||||||
|
|
||||||
/* XXX:
|
/* XXX:
|
||||||
* The CoglObject macros don't support any form of inheritance, so for
|
* The CoglObject macros don't support any form of inheritance, so for
|
||||||
* now we implement the CoglObject support for the CoglBuffer
|
* now we implement the CoglObject support for the CoglBuffer
|
||||||
@ -100,168 +74,6 @@ cogl_is_buffer (void *object)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 void *
|
|
||||||
_cogl_buffer_bind_no_create (CoglBuffer *buffer,
|
|
||||||
CoglBufferBindTarget target)
|
|
||||||
{
|
|
||||||
CoglContext *ctx = buffer->context;
|
|
||||||
|
|
||||||
_COGL_RETURN_VAL_IF_FAIL (buffer != NULL, NULL);
|
|
||||||
|
|
||||||
/* Don't allow binding the buffer to multiple targets at the same time */
|
|
||||||
_COGL_RETURN_VAL_IF_FAIL (ctx->current_buffer[buffer->last_target] != buffer,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
/* Don't allow nesting binds to the same target */
|
|
||||||
_COGL_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GLenum
|
|
||||||
_cogl_buffer_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)
|
|
||||||
if (buffer->context->driver != COGL_DRIVER_GLES1)
|
|
||||||
return GL_STREAM_DRAW;
|
|
||||||
#else
|
|
||||||
return GL_DYNAMIC_DRAW;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
bo_recreate_store (CoglBuffer *buffer)
|
|
||||||
{
|
|
||||||
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 = _cogl_buffer_hints_to_gl_enum (buffer);
|
|
||||||
|
|
||||||
GE( buffer->context, glBufferData (gl_target,
|
|
||||||
buffer->size,
|
|
||||||
NULL,
|
|
||||||
gl_enum) );
|
|
||||||
buffer->store_created = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
|
||||||
bo_map (CoglBuffer *buffer,
|
|
||||||
CoglBufferAccess access,
|
|
||||||
CoglBufferMapHint hints)
|
|
||||||
{
|
|
||||||
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))
|
|
||||||
return NULL;
|
|
||||||
if ((access & COGL_BUFFER_ACCESS_WRITE) &&
|
|
||||||
!cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
target = buffer->last_target;
|
|
||||||
_cogl_buffer_bind_no_create (buffer, target);
|
|
||||||
|
|
||||||
gl_target = convert_bind_target_to_gl_target (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->store_created || (hints & COGL_BUFFER_MAP_HINT_DISCARD))
|
|
||||||
bo_recreate_store (buffer);
|
|
||||||
|
|
||||||
GE_RET( data, ctx, glMapBuffer (gl_target,
|
|
||||||
_cogl_buffer_access_to_gl_enum (access)) );
|
|
||||||
if (data)
|
|
||||||
buffer->flags |= COGL_BUFFER_FLAG_MAPPED;
|
|
||||||
|
|
||||||
_cogl_buffer_unbind (buffer);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
bo_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_unbind (buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static CoglBool
|
|
||||||
bo_set_data (CoglBuffer *buffer,
|
|
||||||
unsigned int offset,
|
|
||||||
const void *data,
|
|
||||||
unsigned int size)
|
|
||||||
{
|
|
||||||
CoglBufferBindTarget target;
|
|
||||||
GLenum gl_target;
|
|
||||||
CoglContext *ctx = buffer->context;
|
|
||||||
|
|
||||||
target = buffer->last_target;
|
|
||||||
_cogl_buffer_bind (buffer, target);
|
|
||||||
|
|
||||||
gl_target = convert_bind_target_to_gl_target (target);
|
|
||||||
|
|
||||||
GE( ctx, glBufferSubData (gl_target, offset, size, data) );
|
|
||||||
|
|
||||||
_cogl_buffer_unbind (buffer);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fallback path, buffer->data points to a malloc'ed buffer.
|
* Fallback path, buffer->data points to a malloc'ed buffer.
|
||||||
*/
|
*/
|
||||||
@ -293,7 +105,7 @@ malloc_set_data (CoglBuffer *buffer,
|
|||||||
|
|
||||||
void
|
void
|
||||||
_cogl_buffer_initialize (CoglBuffer *buffer,
|
_cogl_buffer_initialize (CoglBuffer *buffer,
|
||||||
CoglContext *context,
|
CoglContext *ctx,
|
||||||
size_t size,
|
size_t size,
|
||||||
CoglBufferBindTarget default_target,
|
CoglBufferBindTarget default_target,
|
||||||
CoglBufferUsageHint usage_hint,
|
CoglBufferUsageHint usage_hint,
|
||||||
@ -301,7 +113,7 @@ _cogl_buffer_initialize (CoglBuffer *buffer,
|
|||||||
{
|
{
|
||||||
CoglBool use_malloc = FALSE;
|
CoglBool use_malloc = FALSE;
|
||||||
|
|
||||||
buffer->context = context;
|
buffer->context = ctx;
|
||||||
buffer->flags = COGL_BUFFER_FLAG_NONE;
|
buffer->flags = COGL_BUFFER_FLAG_NONE;
|
||||||
buffer->store_created = FALSE;
|
buffer->store_created = FALSE;
|
||||||
buffer->size = size;
|
buffer->size = size;
|
||||||
@ -314,13 +126,13 @@ _cogl_buffer_initialize (CoglBuffer *buffer,
|
|||||||
if (default_target == COGL_BUFFER_BIND_TARGET_PIXEL_PACK ||
|
if (default_target == COGL_BUFFER_BIND_TARGET_PIXEL_PACK ||
|
||||||
default_target == COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK)
|
default_target == COGL_BUFFER_BIND_TARGET_PIXEL_UNPACK)
|
||||||
{
|
{
|
||||||
if (!(context->private_feature_flags & COGL_PRIVATE_FEATURE_PBOS))
|
if (!(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_PBOS))
|
||||||
use_malloc = TRUE;
|
use_malloc = TRUE;
|
||||||
}
|
}
|
||||||
else if (default_target == COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER ||
|
else if (default_target == COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER ||
|
||||||
default_target == COGL_BUFFER_BIND_TARGET_INDEX_BUFFER)
|
default_target == COGL_BUFFER_BIND_TARGET_INDEX_BUFFER)
|
||||||
{
|
{
|
||||||
if (!(context->private_feature_flags & COGL_PRIVATE_FEATURE_VBOS))
|
if (!(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_VBOS))
|
||||||
use_malloc = TRUE;
|
use_malloc = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,11 +146,12 @@ _cogl_buffer_initialize (CoglBuffer *buffer,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer->vtable.map = bo_map;
|
buffer->vtable.map = ctx->driver_vtable->buffer_map;
|
||||||
buffer->vtable.unmap = bo_unmap;
|
buffer->vtable.unmap = ctx->driver_vtable->buffer_unmap;
|
||||||
buffer->vtable.set_data = bo_set_data;
|
buffer->vtable.set_data = ctx->driver_vtable->buffer_set_data;
|
||||||
|
|
||||||
|
ctx->driver_vtable->buffer_create (buffer);
|
||||||
|
|
||||||
GE( context, glGenBuffers (1, &buffer->gl_handle) );
|
|
||||||
buffer->flags |= COGL_BUFFER_FLAG_BUFFER_OBJECT;
|
buffer->flags |= COGL_BUFFER_FLAG_BUFFER_OBJECT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -350,58 +163,11 @@ _cogl_buffer_fini (CoglBuffer *buffer)
|
|||||||
_COGL_RETURN_IF_FAIL (buffer->immutable_ref == 0);
|
_COGL_RETURN_IF_FAIL (buffer->immutable_ref == 0);
|
||||||
|
|
||||||
if (buffer->flags & COGL_BUFFER_FLAG_BUFFER_OBJECT)
|
if (buffer->flags & COGL_BUFFER_FLAG_BUFFER_OBJECT)
|
||||||
GE( buffer->context, glDeleteBuffers (1, &buffer->gl_handle) );
|
buffer->context->driver_vtable->buffer_destroy (buffer);
|
||||||
else
|
else
|
||||||
g_free (buffer->data);
|
g_free (buffer->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
_cogl_buffer_gl_bind (CoglBuffer *buffer, CoglBufferBindTarget target)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
bo_recreate_store (buffer);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_cogl_buffer_gl_unbind (CoglBuffer *buffer)
|
|
||||||
{
|
|
||||||
CoglContext *ctx = buffer->context;
|
|
||||||
|
|
||||||
_COGL_RETURN_IF_FAIL (buffer != NULL);
|
|
||||||
|
|
||||||
/* the unbind should pair up with a previous bind */
|
|
||||||
_COGL_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
cogl_buffer_get_size (CoglBuffer *buffer)
|
cogl_buffer_get_size (CoglBuffer *buffer)
|
||||||
{
|
{
|
||||||
|
@ -229,6 +229,32 @@ struct _CoglDriverVtable
|
|||||||
void
|
void
|
||||||
(* clip_stack_flush) (CoglClipStack *stack, CoglFramebuffer *framebuffer);
|
(* clip_stack_flush) (CoglClipStack *stack, CoglFramebuffer *framebuffer);
|
||||||
|
|
||||||
|
/* Enables the driver to create some meta data to represent a buffer
|
||||||
|
* but with no corresponding storage allocated yet.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
(* buffer_create) (CoglBuffer *buffer);
|
||||||
|
|
||||||
|
void
|
||||||
|
(* buffer_destroy) (CoglBuffer *buffer);
|
||||||
|
|
||||||
|
/* Maps a buffer into the CPU */
|
||||||
|
void *
|
||||||
|
(* buffer_map) (CoglBuffer *buffer,
|
||||||
|
CoglBufferAccess access,
|
||||||
|
CoglBufferMapHint hints);
|
||||||
|
|
||||||
|
/* Unmaps a buffer */
|
||||||
|
void
|
||||||
|
(* buffer_unmap) (CoglBuffer *buffer);
|
||||||
|
|
||||||
|
/* Uploads data to the buffer without needing to map it necessarily
|
||||||
|
*/
|
||||||
|
CoglBool
|
||||||
|
(* buffer_set_data) (CoglBuffer *buffer,
|
||||||
|
unsigned int offset,
|
||||||
|
const void *data,
|
||||||
|
unsigned int size);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __COGL_DRIVER_H */
|
#endif /* __COGL_DRIVER_H */
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#include "cogl-private.h"
|
#include "cogl-private.h"
|
||||||
#include "cogl1-context.h"
|
#include "cogl1-context.h"
|
||||||
#include "cogl-offscreen.h"
|
#include "cogl-offscreen.h"
|
||||||
|
#include "cogl-attribute-gl-private.h"
|
||||||
|
|
||||||
#ifdef COGL_GL_DEBUG
|
#ifdef COGL_GL_DEBUG
|
||||||
/* GL error to string conversion */
|
/* GL error to string conversion */
|
||||||
@ -446,7 +447,7 @@ cogl_begin_gl (void)
|
|||||||
cogl_pipeline_get_n_layers (pipeline));
|
cogl_pipeline_get_n_layers (pipeline));
|
||||||
|
|
||||||
/* Disable any cached vertex arrays */
|
/* Disable any cached vertex arrays */
|
||||||
_cogl_attribute_disable_cached_arrays ();
|
_cogl_gl_disable_all_attributes (ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -41,4 +41,7 @@ _cogl_gl_flush_attributes_state (CoglFramebuffer *framebuffer,
|
|||||||
CoglAttribute **attributes,
|
CoglAttribute **attributes,
|
||||||
int n_attributes);
|
int n_attributes);
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_gl_disable_all_attributes (CoglContext *ctx);
|
||||||
|
|
||||||
#endif /* _COGL_ATTRIBUTE_GL_PRIVATE_H_ */
|
#endif /* _COGL_ATTRIBUTE_GL_PRIVATE_H_ */
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "cogl-attribute-private.h"
|
#include "cogl-attribute-private.h"
|
||||||
#include "cogl-attribute-gl-private.h"
|
#include "cogl-attribute-gl-private.h"
|
||||||
#include "cogl-pipeline-progend-glsl-private.h"
|
#include "cogl-pipeline-progend-glsl-private.h"
|
||||||
|
#include "cogl-buffer-gl-private.h"
|
||||||
|
|
||||||
typedef struct _ForeachChangedBitState
|
typedef struct _ForeachChangedBitState
|
||||||
{
|
{
|
||||||
@ -396,3 +397,16 @@ _cogl_gl_flush_attributes_state (CoglFramebuffer *framebuffer,
|
|||||||
if (copy)
|
if (copy)
|
||||||
cogl_object_unref (copy);
|
cogl_object_unref (copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_gl_disable_all_attributes (CoglContext *ctx)
|
||||||
|
{
|
||||||
|
_cogl_bitmask_clear_all (&ctx->enable_builtin_attributes_tmp);
|
||||||
|
_cogl_bitmask_clear_all (&ctx->enable_texcoord_attributes_tmp);
|
||||||
|
_cogl_bitmask_clear_all (&ctx->enable_custom_attributes_tmp);
|
||||||
|
|
||||||
|
/* XXX: we can pass a NULL source pipeline here because we know a
|
||||||
|
* source pipeline only needs to be referenced when enabling
|
||||||
|
* attributes. */
|
||||||
|
apply_attribute_enable_updates (ctx, NULL);
|
||||||
|
}
|
||||||
|
62
cogl/driver/gl/cogl-buffer-gl-private.h
Normal file
62
cogl/driver/gl/cogl-buffer-gl-private.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Cogl
|
||||||
|
*
|
||||||
|
* An object oriented GL/GLES Abstraction/Utility Layer
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Intel Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Robert Bragg <robert@linux.intel.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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 (CoglBuffer *buffer,
|
||||||
|
CoglBufferAccess access,
|
||||||
|
CoglBufferMapHint hints);
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_buffer_gl_unmap (CoglBuffer *buffer);
|
||||||
|
|
||||||
|
CoglBool
|
||||||
|
_cogl_buffer_gl_set_data (CoglBuffer *buffer,
|
||||||
|
unsigned int offset,
|
||||||
|
const void *data,
|
||||||
|
unsigned int size);
|
||||||
|
|
||||||
|
void *
|
||||||
|
_cogl_buffer_gl_bind (CoglBuffer *buffer, CoglBufferBindTarget target);
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_buffer_gl_unbind (CoglBuffer *buffer);
|
||||||
|
|
||||||
|
#endif /* _COGL_BUFFER_GL_PRIVATE_H_ */
|
283
cogl/driver/gl/cogl-buffer-gl.c
Normal file
283
cogl/driver/gl/cogl-buffer-gl.c
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
/*
|
||||||
|
* Cogl
|
||||||
|
*
|
||||||
|
* An object oriented GL/GLES Abstraction/Utility Layer
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010,2011,2012 Intel Corporation.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Damien Lespiau <damien.lespiau@intel.com>
|
||||||
|
* Robert Bragg <robert@linux.intel.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "cogl-context-private.h"
|
||||||
|
#include "cogl-buffer-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
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
if (buffer->context->driver != COGL_DRIVER_GLES1)
|
||||||
|
return GL_STREAM_DRAW;
|
||||||
|
#else
|
||||||
|
return GL_DYNAMIC_DRAW;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 void
|
||||||
|
recreate_store (CoglBuffer *buffer)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
GE( buffer->context, glBufferData (gl_target,
|
||||||
|
buffer->size,
|
||||||
|
NULL,
|
||||||
|
gl_enum) );
|
||||||
|
buffer->store_created = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
_COGL_RETURN_VAL_IF_FAIL (buffer != NULL, NULL);
|
||||||
|
|
||||||
|
/* Don't allow binding the buffer to multiple targets at the same time */
|
||||||
|
_COGL_RETURN_VAL_IF_FAIL (ctx->current_buffer[buffer->last_target] != buffer,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Don't allow nesting binds to the same target */
|
||||||
|
_COGL_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 (CoglBuffer *buffer,
|
||||||
|
CoglBufferAccess access,
|
||||||
|
CoglBufferMapHint hints)
|
||||||
|
{
|
||||||
|
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))
|
||||||
|
return NULL;
|
||||||
|
if ((access & COGL_BUFFER_ACCESS_WRITE) &&
|
||||||
|
!cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_WRITE))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
target = buffer->last_target;
|
||||||
|
_cogl_buffer_bind_no_create (buffer, target);
|
||||||
|
|
||||||
|
gl_target = convert_bind_target_to_gl_target (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->store_created || (hints & COGL_BUFFER_MAP_HINT_DISCARD))
|
||||||
|
recreate_store (buffer);
|
||||||
|
|
||||||
|
GE_RET( data, ctx, glMapBuffer (gl_target,
|
||||||
|
_cogl_buffer_access_to_gl_enum (access)) );
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
CoglBool
|
||||||
|
_cogl_buffer_gl_set_data (CoglBuffer *buffer,
|
||||||
|
unsigned int offset,
|
||||||
|
const void *data,
|
||||||
|
unsigned int size)
|
||||||
|
{
|
||||||
|
CoglBufferBindTarget target;
|
||||||
|
GLenum gl_target;
|
||||||
|
CoglContext *ctx = buffer->context;
|
||||||
|
|
||||||
|
target = buffer->last_target;
|
||||||
|
_cogl_buffer_gl_bind (buffer, target);
|
||||||
|
|
||||||
|
gl_target = convert_bind_target_to_gl_target (target);
|
||||||
|
|
||||||
|
GE( ctx, glBufferSubData (gl_target, offset, size, data) );
|
||||||
|
|
||||||
|
_cogl_buffer_gl_unbind (buffer);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
_cogl_buffer_gl_bind (CoglBuffer *buffer, CoglBufferBindTarget target)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
recreate_store (buffer);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_buffer_gl_unbind (CoglBuffer *buffer)
|
||||||
|
{
|
||||||
|
CoglContext *ctx = buffer->context;
|
||||||
|
|
||||||
|
_COGL_RETURN_IF_FAIL (buffer != NULL);
|
||||||
|
|
||||||
|
/* the unbind should pair up with a previous bind */
|
||||||
|
_COGL_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;
|
||||||
|
}
|
@ -29,6 +29,7 @@
|
|||||||
#include "cogl-context-private.h"
|
#include "cogl-context-private.h"
|
||||||
#include "cogl-framebuffer-private.h"
|
#include "cogl-framebuffer-private.h"
|
||||||
#include "cogl-framebuffer-gl-private.h"
|
#include "cogl-framebuffer-gl-private.h"
|
||||||
|
#include "cogl-buffer-gl-private.h"
|
||||||
#include "cogl-error-private.h"
|
#include "cogl-error-private.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "cogl-texture-2d-gl-private.h"
|
#include "cogl-texture-2d-gl-private.h"
|
||||||
#include "cogl-attribute-gl-private.h"
|
#include "cogl-attribute-gl-private.h"
|
||||||
#include "cogl-clip-stack-gl-private.h"
|
#include "cogl-clip-stack-gl-private.h"
|
||||||
|
#include "cogl-buffer-gl-private.h"
|
||||||
|
|
||||||
static CoglBool
|
static CoglBool
|
||||||
_cogl_driver_pixel_format_from_gl_internal (CoglContext *context,
|
_cogl_driver_pixel_format_from_gl_internal (CoglContext *context,
|
||||||
@ -552,4 +553,9 @@ _cogl_driver_gl =
|
|||||||
_cogl_texture_2d_gl_get_data,
|
_cogl_texture_2d_gl_get_data,
|
||||||
_cogl_gl_flush_attributes_state,
|
_cogl_gl_flush_attributes_state,
|
||||||
_cogl_clip_stack_gl_flush,
|
_cogl_clip_stack_gl_flush,
|
||||||
|
_cogl_buffer_gl_create,
|
||||||
|
_cogl_buffer_gl_destroy,
|
||||||
|
_cogl_buffer_gl_map,
|
||||||
|
_cogl_buffer_gl_unmap,
|
||||||
|
_cogl_buffer_gl_set_data,
|
||||||
};
|
};
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "cogl-texture-2d-gl-private.h"
|
#include "cogl-texture-2d-gl-private.h"
|
||||||
#include "cogl-attribute-gl-private.h"
|
#include "cogl-attribute-gl-private.h"
|
||||||
#include "cogl-clip-stack-gl-private.h"
|
#include "cogl-clip-stack-gl-private.h"
|
||||||
|
#include "cogl-buffer-gl-private.h"
|
||||||
|
|
||||||
#ifndef GL_UNSIGNED_INT_24_8
|
#ifndef GL_UNSIGNED_INT_24_8
|
||||||
#define GL_UNSIGNED_INT_24_8 0x84FA
|
#define GL_UNSIGNED_INT_24_8 0x84FA
|
||||||
@ -370,4 +371,9 @@ _cogl_driver_gles =
|
|||||||
NULL, /* texture_2d_get_data */
|
NULL, /* texture_2d_get_data */
|
||||||
_cogl_gl_flush_attributes_state,
|
_cogl_gl_flush_attributes_state,
|
||||||
_cogl_clip_stack_gl_flush,
|
_cogl_clip_stack_gl_flush,
|
||||||
|
_cogl_buffer_gl_create,
|
||||||
|
_cogl_buffer_gl_destroy,
|
||||||
|
_cogl_buffer_gl_map,
|
||||||
|
_cogl_buffer_gl_unmap,
|
||||||
|
_cogl_buffer_gl_set_data,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user