|
|
|
@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
|
|
|
|
|
/*
|
|
|
|
|
gl2wrap_shim.c - vitaGL custom immediate mode shim |
|
|
|
|
Copyright (C) 2023 fgsfds |
|
|
|
|
gl2_shim.c - GL CORE/ES2+ FFP emulation |
|
|
|
|
Copyright (C) 2023 mittorn, fgsfds |
|
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify |
|
|
|
|
it under the terms of the GNU General Public License as published by |
|
|
|
@ -14,9 +14,21 @@ GNU General Public License for more details.
@@ -14,9 +14,21 @@ GNU General Public License for more details.
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
this is a "replacement" for vitaGL's immediate mode tailored specifically for xash |
|
|
|
|
this will only provide performance gains if vitaGL is built with DRAW_SPEEDHACK=1 |
|
|
|
|
since that makes it assume that all vertex data pointers are GPU-mapped |
|
|
|
|
based on vglshim, as it has almost all needed for using glbegins on gles |
|
|
|
|
BufStorage mode should work similar to vglshim with vitagl's DRAW_SPEEDHACK |
|
|
|
|
as it uses gpu-mapped in similar way |
|
|
|
|
|
|
|
|
|
gl2shim will not give much performance gain. It does not batch small drawcalls, just do little copy optimization |
|
|
|
|
It just allows to draw similar way as in native legacy context, but in es/core contexts |
|
|
|
|
|
|
|
|
|
Limitations: |
|
|
|
|
1. Matrix support is very limited, only combined MVP |
|
|
|
|
2. No TexEnv support, multitexture always works in MODULATE mode |
|
|
|
|
3. DrawElements with client pointers will not work on CORE/WEBGL contexts, DrawRangeElements will |
|
|
|
|
4. No quads in arrays drawing (simple DrawArrays(GL_QUADS) may be implemented, but DrawElements not) |
|
|
|
|
5. Textures are enabled with texcoord attribs, not glEnable (can be changed, but who cares?) |
|
|
|
|
6. Begin/End limited to 8192 vertices. It is possible to support more, but need change glVertex logic to split drawcals, which may make it slower |
|
|
|
|
7. Textures internalformat ignored except of removing alpha from RGB textures |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#include "gl_local.h" |
|
|
|
@ -27,6 +39,7 @@ GNU General Public License for more details.
@@ -27,6 +39,7 @@ GNU General Public License for more details.
|
|
|
|
|
#define MAX_SHADERLEN 4096 |
|
|
|
|
// increase this when adding more attributes
|
|
|
|
|
#define MAX_PROGS 32 |
|
|
|
|
// must be LESS GL2_MAX_VERTS
|
|
|
|
|
#define MAX_BEGINEND_VERTS 8192 |
|
|
|
|
void* (APIENTRY* _pglMapBufferRange)(GLenum target, GLsizei offset, GLsizei length, GLbitfield access); |
|
|
|
|
void* (APIENTRY* _pglFlushMappedBufferRange)(GLenum target, GLsizei offset, GLsizei length); |
|
|
|
@ -35,15 +48,15 @@ void (APIENTRY*_pglBufferStorage)( GLenum target,
@@ -35,15 +48,15 @@ void (APIENTRY*_pglBufferStorage)( GLenum target,
|
|
|
|
|
GLsizei size, |
|
|
|
|
const GLvoid * data, |
|
|
|
|
GLbitfield flags); |
|
|
|
|
void (*_pglWaitSync)( void * sync, |
|
|
|
|
void (APIENTRY*_pglWaitSync)( void * sync, |
|
|
|
|
GLbitfield flags, |
|
|
|
|
uint64_t timeout); |
|
|
|
|
GLuint (*_pglClientWaitSync)( void * sync, |
|
|
|
|
GLuint (APIENTRY*_pglClientWaitSync)( void * sync, |
|
|
|
|
GLbitfield flags, |
|
|
|
|
uint64_t timeout); |
|
|
|
|
void *(*_pglFenceSync)( GLenum condition, |
|
|
|
|
void *(APIENTRY*_pglFenceSync)( GLenum condition, |
|
|
|
|
GLbitfield flags); |
|
|
|
|
void (*_pglDeleteSync)( void * sync ); |
|
|
|
|
void (APIENTRY*_pglDeleteSync)( void * sync ); |
|
|
|
|
|
|
|
|
|
extern ref_api_t gEngfuncs; |
|
|
|
|
|
|
|
|
@ -120,7 +133,7 @@ static struct
@@ -120,7 +133,7 @@ static struct
|
|
|
|
|
qboolean async; // enable MAP_UNSYNCHRONIZED_BIT on temporary mappings
|
|
|
|
|
qboolean force_flush; // enable MAP_FLUSH_EXPLICIT_BIT and FlushMappedBufferRange calls
|
|
|
|
|
uint32_t cycle_buffers; // cycle N buffers during draw to reduce locking in non-incremental mode
|
|
|
|
|
uint32_t version; |
|
|
|
|
uint32_t version; // glsl version to use
|
|
|
|
|
} gl2wrap_config; |
|
|
|
|
|
|
|
|
|
static struct |
|
|
|
@ -435,9 +448,9 @@ static void GL2_InitTriQuads( void )
@@ -435,9 +448,9 @@ static void GL2_InitTriQuads( void )
|
|
|
|
|
for( i = 0; i < (!!_pglDrawRangeElementsBaseVertex?1:4); i++ ) |
|
|
|
|
{ |
|
|
|
|
int j; |
|
|
|
|
GLushort triquads_array[TRIQUADS_SIZE * 6]; |
|
|
|
|
GLushort triquads_array[TRIQUADS_SIZE]; |
|
|
|
|
|
|
|
|
|
for( j = 0; j < TRIQUADS_SIZE; j++ ) |
|
|
|
|
for( j = 0; j < TRIQUADS_SIZE / 6; j++ ) |
|
|
|
|
{ |
|
|
|
|
triquads_array[j * 6] = j * 4 + i; |
|
|
|
|
triquads_array[j * 6 + 1] = j * 4 + 1 + i; |
|
|
|
@ -644,8 +657,6 @@ static void GL2_ResetPersistentBuffer( void )
@@ -644,8 +657,6 @@ static void GL2_ResetPersistentBuffer( void )
|
|
|
|
|
int size = GL2_MAX_VERTS * gl2wrap_attr_size[i] * sizeof( GLfloat ); |
|
|
|
|
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap.attrbufobj[i][gl2wrap.attrbufcycle] ); |
|
|
|
|
if(gl2wrap_config.buf_storage) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
pglUnmapBufferARB(GL_ARRAY_BUFFER_ARB); |
|
|
|
@ -718,8 +729,17 @@ static void APIENTRY GL2_Begin( GLenum prim )
@@ -718,8 +729,17 @@ static void APIENTRY GL2_Begin( GLenum prim )
|
|
|
|
|
// pos always enabled
|
|
|
|
|
gl2wrap.cur_flags |= 1 << GL2_ATTR_POS; |
|
|
|
|
} |
|
|
|
|
void (*_pglMemoryBarrier)(GLbitfield barriers); |
|
|
|
|
void (APIENTRY*_pglMemoryBarrier)(GLbitfield barriers); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
============================== |
|
|
|
|
UpdateIncrementalBuffer |
|
|
|
|
|
|
|
|
|
glBufferStorage allows to write directly without mapping buffer every time before draw |
|
|
|
|
This allows keep VAO unchanged and fastly build needed pipeline in driver for every program variant |
|
|
|
|
When buffer storage not supported, we still may use cached VAO, but map/unmap it every time writing new data |
|
|
|
|
============================== |
|
|
|
|
*/ |
|
|
|
|
static void GL2_UpdateIncrementalBuffer( gl2wrap_prog_t *prog, int count ) |
|
|
|
|
{ |
|
|
|
|
int i; |
|
|
|
@ -750,6 +770,7 @@ static void GL2_UpdateIncrementalBuffer( gl2wrap_prog_t *prog, int count )
@@ -750,6 +770,7 @@ static void GL2_UpdateIncrementalBuffer( gl2wrap_prog_t *prog, int count )
|
|
|
|
|
} |
|
|
|
|
else if(!gl2wrap_config.coherent) |
|
|
|
|
{ |
|
|
|
|
// non-coherent buffers anyway require unmapping or flushing after write
|
|
|
|
|
for( i = 0; i < GL2_ATTR_MAX; i++) |
|
|
|
|
{ |
|
|
|
|
if ( prog->attridx[i] >= 0 ) |
|
|
|
@ -852,10 +873,18 @@ void GL2_FlushPrims( void )
@@ -852,10 +873,18 @@ void GL2_FlushPrims( void )
|
|
|
|
|
|
|
|
|
|
if(gl2wrap.prim == GL_QUADS) |
|
|
|
|
{ |
|
|
|
|
// simple case, one quad may draw like polygon(4)
|
|
|
|
|
if(count == 4) |
|
|
|
|
rpglDrawArrays( GL_TRIANGLE_FAN, startindex, count ); |
|
|
|
|
else if(_pglDrawRangeElementsBaseVertex) |
|
|
|
|
{ |
|
|
|
|
/*
|
|
|
|
|
* Opengl deprecated QUADS, but made some workarounds availiable |
|
|
|
|
* idea: bound static index array that will repeat 0 1 2 0 2 3 4 5 6 4 6 7... |
|
|
|
|
* sequence and draw source arrays. But our array may have different offset |
|
|
|
|
* When DrawRangeElementsBaseVertex unavailiable, we need build 4 different index arrays (as sequence have period 4) |
|
|
|
|
* or just put 0-4 offset when it's availiable |
|
|
|
|
* */ |
|
|
|
|
pglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, gl2wrap.triquads_ibo[0] ); |
|
|
|
|
_pglDrawRangeElementsBaseVertex( GL_TRIANGLES, startindex, startindex + count, Q_min(count / 4 * 6,TRIQUADS_SIZE * 6 - startindex), GL_UNSIGNED_SHORT, (void*)(size_t)(startindex / 4 * 6 * 2), startindex % 4 ); |
|
|
|
|
pglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0); |
|
|
|
@ -873,15 +902,17 @@ void GL2_FlushPrims( void )
@@ -873,15 +902,17 @@ void GL2_FlushPrims( void )
|
|
|
|
|
pglBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else if( gl2wrap.prim == GL_POLYGON ) |
|
|
|
|
else if( gl2wrap.prim == GL_POLYGON ) // does it have any difference with TRIFAN?
|
|
|
|
|
rpglDrawArrays( GL_TRIANGLE_FAN, startindex, count ); |
|
|
|
|
else |
|
|
|
|
else // TRIANGLES, LINES, TRISTRIP, TRIFAN supported anyway
|
|
|
|
|
rpglDrawArrays( gl2wrap.prim, startindex, count ); |
|
|
|
|
|
|
|
|
|
_leave: |
|
|
|
|
if(gl2wrap_config.vao_mandatory) |
|
|
|
|
{ |
|
|
|
|
pglBindVertexArray(0); |
|
|
|
|
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); |
|
|
|
|
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
gl2wrap.prim = GL_NONE; |
|
|
|
|
gl2wrap.begin = gl2wrap.end; |
|
|
|
@ -1027,12 +1058,7 @@ static void APIENTRY GL2_Color4f( GLfloat r, GLfloat g, GLfloat b, GLfloat a )
@@ -1027,12 +1058,7 @@ static void APIENTRY GL2_Color4f( GLfloat r, GLfloat g, GLfloat b, GLfloat a )
|
|
|
|
|
if ( gl2wrap.prim ) |
|
|
|
|
{ |
|
|
|
|
// HACK: enable color attribute if we're using color inside a Begin-End pair
|
|
|
|
|
GLfloat *p = gl2wrap.attrbuf[GL2_ATTR_COLOR] + gl2wrap.end * 4; |
|
|
|
|
gl2wrap.cur_flags |= 1 << GL2_ATTR_COLOR; |
|
|
|
|
*p++ = r; |
|
|
|
|
*p++ = g; |
|
|
|
|
*p++ = b; |
|
|
|
|
*p++ = a; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1137,6 +1163,15 @@ static void APIENTRY GL2_Disable( GLenum e )
@@ -1137,6 +1163,15 @@ static void APIENTRY GL2_Disable( GLenum e )
|
|
|
|
|
rpglDisable(e); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=========================== |
|
|
|
|
|
|
|
|
|
Limited matrix emulation |
|
|
|
|
|
|
|
|
|
=========================== |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
static void APIENTRY GL2_MatrixMode( GLenum m ) |
|
|
|
|
{ |
|
|
|
|
// if(gl2wrap_matrix.mode == m)
|
|
|
|
@ -1221,6 +1256,7 @@ static void GL2_Mul4x4(const GLfloat *in0, const GLfloat *in1, GLfloat *out)
@@ -1221,6 +1256,7 @@ static void GL2_Mul4x4(const GLfloat *in0, const GLfloat *in1, GLfloat *out)
|
|
|
|
|
|
|
|
|
|
static void GL2_UpdateMVP( gl2wrap_prog_t *prog ) |
|
|
|
|
{ |
|
|
|
|
// use bitset to determine if need update matrix for this prog
|
|
|
|
|
if( gl2wrap_matrix.update & ( 1U << prog->flags ) ) |
|
|
|
|
{ |
|
|
|
|
gl2wrap_matrix.update &= ~( 1U << prog->flags ); |
|
|
|
@ -1242,6 +1278,13 @@ static void APIENTRY GL2_DepthRange(GLdouble far, GLdouble near)
@@ -1242,6 +1278,13 @@ static void APIENTRY GL2_DepthRange(GLdouble far, GLdouble near)
|
|
|
|
|
_pglDepthRangef(far, near); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
====================== |
|
|
|
|
|
|
|
|
|
Array drawing |
|
|
|
|
|
|
|
|
|
===================== |
|
|
|
|
*/ |
|
|
|
|
typedef struct gl2wrap_arraypointer_s |
|
|
|
|
{ |
|
|
|
|
const void *userptr; |
|
|
|
@ -1318,6 +1361,148 @@ static void APIENTRY GL2_DisableClientState( GLenum array )
@@ -1318,6 +1361,148 @@ static void APIENTRY GL2_DisableClientState( GLenum array )
|
|
|
|
|
gl2wrap_arrays.flags &= ~(1 << idx); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=========================== |
|
|
|
|
UploadBufferData |
|
|
|
|
|
|
|
|
|
Dumb buffer upload |
|
|
|
|
Used when uploading very large buffers or when persistent/incremental buffers disabled (MapBuffer unavailiable?) |
|
|
|
|
=========================== |
|
|
|
|
*/ |
|
|
|
|
static void GL2_UploadBufferData( gl2wrap_prog_t *prog, int size, GLuint start, GLuint end, int stride, int attr ) |
|
|
|
|
{ |
|
|
|
|
if( !gl2wrap_arrays.ptr[attr].vbo_fb ) |
|
|
|
|
{ |
|
|
|
|
gl2wrap_arrays.ptr[attr].vbo_fb = malloc(4 * gl2wrap_config.cycle_buffers); |
|
|
|
|
pglGenBuffersARB( gl2wrap_config.cycle_buffers, gl2wrap_arrays.ptr[attr].vbo_fb ); |
|
|
|
|
} |
|
|
|
|
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap_arrays.ptr[attr].vbo_fb[gl2wrap_arrays.ptr[attr].vbo_cycle] ); |
|
|
|
|
gl2wrap_arrays.ptr[attr].vbo_cycle = (gl2wrap_arrays.ptr[attr].vbo_cycle + 1) % gl2wrap_config.cycle_buffers; |
|
|
|
|
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, end * stride, gl2wrap_arrays.ptr[attr].userptr, GL_STREAM_DRAW_ARB ); |
|
|
|
|
pglVertexAttribPointerARB( prog->attridx[attr], gl2wrap_arrays.ptr[attr].size, gl2wrap_arrays.ptr[attr].type, attr == GL2_ATTR_COLOR, gl2wrap_arrays.ptr[attr].stride, 0 ); |
|
|
|
|
} |
|
|
|
|
/*
|
|
|
|
|
=========================== |
|
|
|
|
UpdatePersistentArrayBuffer |
|
|
|
|
|
|
|
|
|
Persistent array always mapped to stream_pointer with BufferStorage |
|
|
|
|
just memcopy it into and flush when overflowed |
|
|
|
|
=========================== |
|
|
|
|
*/ |
|
|
|
|
static void GL2_UpdatePersistentArrayBuffer( gl2wrap_prog_t *prog, int size, int offset, GLuint start, GLuint end, int stride, int attr ) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
if(gl2wrap_arrays.stream_counter + size > GL2_MAX_VERTS * 64) |
|
|
|
|
{ |
|
|
|
|
pglUnmapBufferARB(GL_ARRAY_BUFFER_ARB); |
|
|
|
|
gl2wrap_arrays.stream_counter = 0; |
|
|
|
|
gl2wrap_arrays.stream_pointer = _pglMapBufferRange(GL_ARRAY_BUFFER_ARB, |
|
|
|
|
0, |
|
|
|
|
GL2_MAX_VERTS * 64, |
|
|
|
|
0x0002 //GL_MAP_WRITE_BIT
|
|
|
|
|
// | 0x0004// GL_MAP_INVALIDATE_RANGE_BIT.
|
|
|
|
|
// | 0x0008 // GL_MAP_INVALIDATE_BUFFER_BIT
|
|
|
|
|
// |0x0020 //GL_MAP_UNSYNCHRONIZED_BIT
|
|
|
|
|
|(!gl2wrap_config.coherent?0x0010:0) // GL_MAP_FLUSH_EXPLICIT_BIT
|
|
|
|
|
| 0X40 |
|
|
|
|
| (gl2wrap_config.coherent?0x00000080:0) // GL_MAP_COHERENT_BIT
|
|
|
|
|
); |
|
|
|
|
//i = -1;
|
|
|
|
|
//continue;
|
|
|
|
|
size = end * stride, offset = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
memcpy(((char*)gl2wrap_arrays.stream_pointer) + gl2wrap_arrays.stream_counter, ((char*)gl2wrap_arrays.ptr[attr].userptr) + offset, size); |
|
|
|
|
if( !gl2wrap_config.coherent ) |
|
|
|
|
_pglFlushMappedBufferRange( GL_ARRAY_BUFFER_ARB, gl2wrap_arrays.stream_counter, size ); |
|
|
|
|
pglVertexAttribPointerARB( prog->attridx[attr], gl2wrap_arrays.ptr[attr].size, gl2wrap_arrays.ptr[attr].type, attr == GL2_ATTR_COLOR, gl2wrap_arrays.ptr[attr].stride, (void*)(gl2wrap_arrays.stream_counter - offset) ); |
|
|
|
|
gl2wrap_arrays.stream_counter += size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=========================== |
|
|
|
|
UpdateIncrementalArrayBuffer |
|
|
|
|
|
|
|
|
|
Like persistent buffer, but map every time when copying data when BufferStorage unavailiable |
|
|
|
|
=========================== |
|
|
|
|
*/ |
|
|
|
|
static void GL2_UpdateIncrementalArrayBuffer( gl2wrap_prog_t *prog, int size, int offset, GLuint start, GLuint end, int stride, int attr ) |
|
|
|
|
{ |
|
|
|
|
void *mem; |
|
|
|
|
qboolean inv = false; |
|
|
|
|
if(gl2wrap_arrays.stream_counter + size > GL2_MAX_VERTS * 64) |
|
|
|
|
size = end * stride, offset = 0, gl2wrap_arrays.stream_counter = 0, inv = true; |
|
|
|
|
mem = _pglMapBufferRange(GL_ARRAY_BUFFER_ARB, |
|
|
|
|
gl2wrap_arrays.stream_counter, |
|
|
|
|
size, |
|
|
|
|
0x0002 //GL_MAP_WRITE_BIT
|
|
|
|
|
| 0x0004// GL_MAP_INVALIDATE_RANGE_BIT.
|
|
|
|
|
| (inv?0x0008:0) // GL_MAP_INVALIDATE_BUFFER_BIT
|
|
|
|
|
|(gl2wrap_config.async ? 0x0020:0) //GL_MAP_UNSYNCHRONIZED_BIT
|
|
|
|
|
|(gl2wrap_config.force_flush ? 0x0010:0) // GL_MAP_FLUSH_EXPLICIT_BIT
|
|
|
|
|
// GL_MAP_COHERENT_BIT
|
|
|
|
|
); |
|
|
|
|
memcpy(mem, ((char*)gl2wrap_arrays.ptr[attr].userptr) + offset, size); |
|
|
|
|
if(gl2wrap_config.force_flush) |
|
|
|
|
_pglFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, 0, size); |
|
|
|
|
pglUnmapBufferARB(GL_ARRAY_BUFFER_ARB); |
|
|
|
|
pglVertexAttribPointerARB( prog->attridx[attr], gl2wrap_arrays.ptr[attr].size, gl2wrap_arrays.ptr[attr].type, attr == GL2_ATTR_COLOR, gl2wrap_arrays.ptr[attr].stride, (void*)(gl2wrap_arrays.stream_counter - offset) ); |
|
|
|
|
gl2wrap_arrays.stream_counter += size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=========================== |
|
|
|
|
AllocArrayPersistenStorage |
|
|
|
|
|
|
|
|
|
Prepare BufferStorage |
|
|
|
|
=========================== |
|
|
|
|
*/ |
|
|
|
|
static void GL2_AllocArrayPersistenStorage( void ) |
|
|
|
|
{ |
|
|
|
|
pglGenBuffersARB( 1, &gl2wrap_arrays.stream_buffer ); |
|
|
|
|
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap_arrays.stream_buffer ); |
|
|
|
|
_pglBufferStorage( GL_ARRAY_BUFFER_ARB, GL2_MAX_VERTS * 64, NULL, |
|
|
|
|
0x0002 //GL_MAP_WRITE_BIT
|
|
|
|
|
| (gl2wrap_config.coherent?0x00000080:0) |
|
|
|
|
| 0x40 |
|
|
|
|
); |
|
|
|
|
gl2wrap_arrays.stream_pointer = _pglMapBufferRange(GL_ARRAY_BUFFER_ARB, |
|
|
|
|
0, |
|
|
|
|
GL2_MAX_VERTS * 64, |
|
|
|
|
0x0002 //GL_MAP_WRITE_BIT
|
|
|
|
|
// | 0x0004// GL_MAP_INVALIDATE_RANGE_BIT.
|
|
|
|
|
// | 0x0008 // GL_MAP_INVALIDATE_BUFFER_BIT
|
|
|
|
|
// |0x0020 //GL_MAP_UNSYNCHRONIZED_BIT
|
|
|
|
|
// |0x0010 // GL_MAP_FLUSH_EXPLICIT_BIT
|
|
|
|
|
| (!gl2wrap_config.coherent?0x0010:0) |
|
|
|
|
| 0X40 |
|
|
|
|
| (gl2wrap_config.coherent?0x00000080:0) // GL_MAP_COHERENT_BIT
|
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void GL2_AllocArrays( void ) |
|
|
|
|
{ |
|
|
|
|
if( gl2wrap_config.buf_storage && !gl2wrap_arrays.stream_pointer ) |
|
|
|
|
GL2_AllocArrayPersistenStorage(); |
|
|
|
|
else if(!gl2wrap_config.buf_storage && gl2wrap_config.incremental && !gl2wrap_arrays.stream_buffer) |
|
|
|
|
{ |
|
|
|
|
// prepare incremental buffer
|
|
|
|
|
pglGenBuffersARB( 1, &gl2wrap_arrays.stream_buffer ); |
|
|
|
|
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap_arrays.stream_buffer ); |
|
|
|
|
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, GL2_MAX_VERTS * 64, NULL, GL_STREAM_DRAW_ARB ); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
====================== |
|
|
|
|
SetupArrays |
|
|
|
|
|
|
|
|
|
If vao usage mandatory, use persistent/incremental buffers when possible |
|
|
|
|
else just set client pointers to default VAO |
|
|
|
|
Usage of client pointers is forbidden with non-default VAO and unavailiable in Core |
|
|
|
|
====================== |
|
|
|
|
*/ |
|
|
|
|
static void GL2_SetupArrays( GLuint start, GLuint end ) |
|
|
|
|
{ |
|
|
|
|
gl2wrap_prog_t *prog; |
|
|
|
@ -1347,9 +1532,11 @@ static void GL2_SetupArrays( GLuint start, GLuint end )
@@ -1347,9 +1532,11 @@ static void GL2_SetupArrays( GLuint start, GLuint end )
|
|
|
|
|
{ |
|
|
|
|
if(prog->attridx[i] < 0) |
|
|
|
|
continue; |
|
|
|
|
if( flags & (1 << i) ) |
|
|
|
|
if( flags & (1 << i) ) // attribute is enabled
|
|
|
|
|
{ |
|
|
|
|
pglEnableVertexAttribArrayARB( prog->attridx[i] ); |
|
|
|
|
// sometimes usage of client pointers may be faster, sometimes not
|
|
|
|
|
// anyway gl core disallows that, so try use streaming
|
|
|
|
|
if( gl2wrap_config.vao_mandatory && !gl2wrap_arrays.ptr[i].vbo ) |
|
|
|
|
{ |
|
|
|
|
// detect stride by type
|
|
|
|
@ -1364,41 +1551,12 @@ static void GL2_SetupArrays( GLuint start, GLuint end )
@@ -1364,41 +1551,12 @@ static void GL2_SetupArrays( GLuint start, GLuint end )
|
|
|
|
|
stride = gl2wrap_arrays.ptr[i].size * 4; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if( gl2wrap_config.buf_storage && !gl2wrap_arrays.stream_pointer ) |
|
|
|
|
{ |
|
|
|
|
pglGenBuffersARB( 1, &gl2wrap_arrays.stream_buffer ); |
|
|
|
|
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap_arrays.stream_buffer ); |
|
|
|
|
_pglBufferStorage( GL_ARRAY_BUFFER_ARB, GL2_MAX_VERTS * 64, NULL, |
|
|
|
|
0x0002 //GL_MAP_WRITE_BIT
|
|
|
|
|
| (gl2wrap_config.coherent?0x00000080:0) |
|
|
|
|
| 0x40 |
|
|
|
|
); |
|
|
|
|
gl2wrap_arrays.stream_pointer = _pglMapBufferRange(GL_ARRAY_BUFFER_ARB, |
|
|
|
|
0, |
|
|
|
|
GL2_MAX_VERTS * 64, |
|
|
|
|
0x0002 //GL_MAP_WRITE_BIT
|
|
|
|
|
// | 0x0004// GL_MAP_INVALIDATE_RANGE_BIT.
|
|
|
|
|
// | 0x0008 // GL_MAP_INVALIDATE_BUFFER_BIT
|
|
|
|
|
// |0x0020 //GL_MAP_UNSYNCHRONIZED_BIT
|
|
|
|
|
// |0x0010 // GL_MAP_FLUSH_EXPLICIT_BIT
|
|
|
|
|
| (!gl2wrap_config.coherent?0x0010:0) |
|
|
|
|
| 0X40 |
|
|
|
|
| (gl2wrap_config.coherent?0x00000080:0) // GL_MAP_COHERENT_BIT
|
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
else if(!gl2wrap_config.buf_storage && gl2wrap_config.incremental && !gl2wrap_arrays.stream_buffer) |
|
|
|
|
{ |
|
|
|
|
pglGenBuffersARB( 1, &gl2wrap_arrays.stream_buffer ); |
|
|
|
|
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap_arrays.stream_buffer ); |
|
|
|
|
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, GL2_MAX_VERTS * 64, NULL, GL_STREAM_DRAW_ARB ); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap_arrays.stream_buffer ); |
|
|
|
|
} |
|
|
|
|
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap_arrays.stream_buffer ); |
|
|
|
|
if(!end) |
|
|
|
|
{ |
|
|
|
|
// we cannot handle this case in VAO without known buffer length
|
|
|
|
|
// only workaround is scanning index array to determine buffer limits, but it is slow,
|
|
|
|
|
// so just do not use DrawElements when DrawRangeElements availiable
|
|
|
|
|
pglDisableVertexAttribArrayARB( prog->attridx[i] ); |
|
|
|
|
gEngfuncs.Con_Printf(S_ERROR "NON-vbo array for DrawElements call, SKIPPING!\n"); |
|
|
|
|
continue; |
|
|
|
@ -1406,71 +1564,22 @@ static void GL2_SetupArrays( GLuint start, GLuint end )
@@ -1406,71 +1564,22 @@ static void GL2_SetupArrays( GLuint start, GLuint end )
|
|
|
|
|
size = (end - start) * stride; |
|
|
|
|
offset = start * stride; |
|
|
|
|
|
|
|
|
|
// Logical buffer start can lie before real buffer start
|
|
|
|
|
// but attrib pointer cannot have negative buffer offset
|
|
|
|
|
if( gl2wrap_arrays.stream_counter < offset ) |
|
|
|
|
size = end * stride, offset = 0; |
|
|
|
|
|
|
|
|
|
if( (!gl2wrap_config.buf_storage && !gl2wrap_config.incremental) || size > GL2_MAX_VERTS * 32) /// TODO: support incremental for !buf_storage
|
|
|
|
|
if( (!gl2wrap_config.buf_storage && !gl2wrap_config.incremental) || size > GL2_MAX_VERTS * 32) |
|
|
|
|
{ |
|
|
|
|
if( !gl2wrap_arrays.ptr[i].vbo_fb ) |
|
|
|
|
{ |
|
|
|
|
gl2wrap_arrays.ptr[i].vbo_fb = malloc(4 * gl2wrap_config.cycle_buffers); |
|
|
|
|
pglGenBuffersARB( gl2wrap_config.cycle_buffers, gl2wrap_arrays.ptr[i].vbo_fb ); |
|
|
|
|
} |
|
|
|
|
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap_arrays.ptr[i].vbo_fb[gl2wrap_arrays.ptr[i].vbo_cycle] ); |
|
|
|
|
gl2wrap_arrays.ptr[i].vbo_cycle = (gl2wrap_arrays.ptr[i].vbo_cycle + 1) % gl2wrap_config.cycle_buffers; |
|
|
|
|
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, end * stride, gl2wrap_arrays.ptr[i].userptr, GL_STREAM_DRAW_ARB ); |
|
|
|
|
pglVertexAttribPointerARB( prog->attridx[i], gl2wrap_arrays.ptr[i].size, gl2wrap_arrays.ptr[i].type, i == GL2_ATTR_COLOR, gl2wrap_arrays.ptr[i].stride, 0 ); |
|
|
|
|
GL2_UploadBufferData( prog, size , start, end, stride, i ); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
if(!gl2wrap_config.buf_storage && gl2wrap_config.incremental) |
|
|
|
|
{ |
|
|
|
|
void *mem; |
|
|
|
|
qboolean inv = false; |
|
|
|
|
if(gl2wrap_arrays.stream_counter + size > GL2_MAX_VERTS * 64) |
|
|
|
|
size = end * stride, offset = 0, gl2wrap_arrays.stream_counter = 0, inv = true; |
|
|
|
|
mem = _pglMapBufferRange(GL_ARRAY_BUFFER_ARB, |
|
|
|
|
gl2wrap_arrays.stream_counter, |
|
|
|
|
size, |
|
|
|
|
0x0002 //GL_MAP_WRITE_BIT
|
|
|
|
|
| 0x0004// GL_MAP_INVALIDATE_RANGE_BIT.
|
|
|
|
|
| (inv?0x0008:0) // GL_MAP_INVALIDATE_BUFFER_BIT
|
|
|
|
|
|(gl2wrap_config.async ? 0x0020:0) //GL_MAP_UNSYNCHRONIZED_BIT
|
|
|
|
|
|(gl2wrap_config.force_flush ? 0x0010:0) // GL_MAP_FLUSH_EXPLICIT_BIT
|
|
|
|
|
// GL_MAP_COHERENT_BIT
|
|
|
|
|
); |
|
|
|
|
memcpy(mem, ((char*)gl2wrap_arrays.ptr[i].userptr) + offset, size); |
|
|
|
|
if(gl2wrap_config.force_flush) |
|
|
|
|
_pglFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, 0, size); |
|
|
|
|
pglUnmapBufferARB(GL_ARRAY_BUFFER_ARB); |
|
|
|
|
pglVertexAttribPointerARB( prog->attridx[i], gl2wrap_arrays.ptr[i].size, gl2wrap_arrays.ptr[i].type, i == GL2_ATTR_COLOR, gl2wrap_arrays.ptr[i].stride, (void*)(gl2wrap_arrays.stream_counter - offset) ); |
|
|
|
|
gl2wrap_arrays.stream_counter += size; |
|
|
|
|
GL2_UpdateIncrementalArrayBuffer( prog, size, offset, start, end, stride, i); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
if(gl2wrap_arrays.stream_counter + size > GL2_MAX_VERTS * 64) |
|
|
|
|
{ |
|
|
|
|
pglUnmapBufferARB(GL_ARRAY_BUFFER_ARB); |
|
|
|
|
gl2wrap_arrays.stream_counter = 0; |
|
|
|
|
gl2wrap_arrays.stream_pointer = _pglMapBufferRange(GL_ARRAY_BUFFER_ARB, |
|
|
|
|
0, |
|
|
|
|
GL2_MAX_VERTS * 64, |
|
|
|
|
0x0002 //GL_MAP_WRITE_BIT
|
|
|
|
|
// | 0x0004// GL_MAP_INVALIDATE_RANGE_BIT.
|
|
|
|
|
// | 0x0008 // GL_MAP_INVALIDATE_BUFFER_BIT
|
|
|
|
|
// |0x0020 //GL_MAP_UNSYNCHRONIZED_BIT
|
|
|
|
|
|(!gl2wrap_config.coherent?0x0010:0) // GL_MAP_FLUSH_EXPLICIT_BIT
|
|
|
|
|
| 0X40 |
|
|
|
|
| (gl2wrap_config.coherent?0x00000080:0) // GL_MAP_COHERENT_BIT
|
|
|
|
|
); |
|
|
|
|
//i = -1;
|
|
|
|
|
//continue;
|
|
|
|
|
size = end * stride, offset = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
memcpy(((char*)gl2wrap_arrays.stream_pointer) + gl2wrap_arrays.stream_counter, ((char*)gl2wrap_arrays.ptr[i].userptr) + offset, size); |
|
|
|
|
if( !gl2wrap_config.coherent ) |
|
|
|
|
_pglFlushMappedBufferRange( GL_ARRAY_BUFFER_ARB, gl2wrap_arrays.stream_counter, size ); |
|
|
|
|
pglVertexAttribPointerARB( prog->attridx[i], gl2wrap_arrays.ptr[i].size, gl2wrap_arrays.ptr[i].type, i == GL2_ATTR_COLOR, gl2wrap_arrays.ptr[i].stride, (void*)(gl2wrap_arrays.stream_counter - offset) ); |
|
|
|
|
gl2wrap_arrays.stream_counter += size; |
|
|
|
|
GL2_UpdatePersistentArrayBuffer( prog, size, offset, start, end, stride, i); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
@ -1489,6 +1598,7 @@ static void GL2_SetupArrays( GLuint start, GLuint end )
@@ -1489,6 +1598,7 @@ static void GL2_SetupArrays( GLuint start, GLuint end )
|
|
|
|
|
pglDisableVertexAttribArrayARB( prog->attridx[i] ); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// restore state
|
|
|
|
|
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap_state.vbo ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1621,5 +1731,6 @@ void GL2_ShimInstall( void )
@@ -1621,5 +1731,6 @@ void GL2_ShimInstall( void )
|
|
|
|
|
#ifdef QUAD_BATCH |
|
|
|
|
GL2_OVERRIDE_PTR_B( BindTexture ) |
|
|
|
|
#endif |
|
|
|
|
GL2_AllocArrays(); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|