2012-11-01 16:19:01 +01:00
// Copyright (c) 2012- PPSSPP Project.
// 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
2012-11-04 23:01:49 +01:00
// the Free Software Foundation, version 2.0 or later versions.
2012-11-01 16:19:01 +01:00
// This program 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 General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
2013-10-09 16:08:36 +02:00
# include "base/logging.h"
2013-01-11 19:03:16 +01:00
# include "base/timeutil.h"
2013-01-29 00:48:13 +01:00
# include "Common/MemoryUtil.h"
2013-04-20 20:20:03 +02:00
# include "Core/MemMap.h"
# include "Core/System.h"
# include "Core/Reporting.h"
# include "Core/Config.h"
# include "Core/CoreTiming.h"
2017-03-03 14:15:27 +01:00
# include "gfx/gl_debug_log.h"
2015-05-13 22:28:02 +02:00
# include "profiler/profiler.h"
2013-04-20 20:20:03 +02:00
# include "GPU/Math3D.h"
# include "GPU/GPUState.h"
# include "GPU/ge_constants.h"
2012-11-01 16:19:01 +01:00
2014-03-25 00:21:04 -07:00
# include "GPU/Common/TextureDecoder.h"
2013-10-13 20:47:52 -07:00
# include "GPU/Common/SplineCommon.h"
2014-09-10 10:44:22 +02:00
# include "GPU/Common/VertexDecoderCommon.h"
2014-09-13 13:27:42 +02:00
# include "GPU/Common/SoftwareTransformCommon.h"
2018-09-01 08:32:03 -07:00
# include "GPU/Debugger/Debugger.h"
2017-01-21 22:16:30 +01:00
# include "GPU/GLES/FragmentTestCacheGLES.h"
# include "GPU/GLES/StateMappingGLES.h"
# include "GPU/GLES/TextureCacheGLES.h"
2016-04-10 10:27:28 +02:00
# include "GPU/GLES/DrawEngineGLES.h"
2017-01-21 22:16:30 +01:00
# include "GPU/GLES/ShaderManagerGLES.h"
2016-04-10 10:27:28 +02:00
# include "GPU/GLES/GPU_GLES.h"
2012-11-01 16:19:01 +01:00
2017-12-12 14:07:52 +01:00
const GLuint glprim [ 8 ] = {
2012-11-01 16:19:01 +01:00
GL_POINTS ,
GL_LINES ,
GL_LINE_STRIP ,
GL_TRIANGLES ,
GL_TRIANGLE_STRIP ,
GL_TRIANGLE_FAN ,
2013-12-09 13:45:17 +01:00
GL_TRIANGLES ,
2016-04-10 10:59:23 +02:00
// Rectangles need to be expanded into triangles.
2012-11-01 16:19:01 +01:00
} ;
2013-01-29 00:48:13 +01:00
enum {
2013-10-27 14:43:58 -07:00
TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof ( TransformedVertex )
2013-01-29 00:48:13 +01:00
} ;
2013-08-01 00:13:58 +02:00
# define VERTEXCACHE_DECIMATION_INTERVAL 17
2015-12-23 01:29:42 -08:00
# define VERTEXCACHE_NAME_DECIMATION_INTERVAL 41
2015-12-23 10:02:01 -08:00
# define VERTEXCACHE_NAME_DECIMATION_MAX 100
2014-06-07 16:15:37 -07:00
# define VERTEXCACHE_NAME_CACHE_SIZE 64
2015-12-23 10:02:01 -08:00
# define VERTEXCACHE_NAME_CACHE_FULL_BYTES (1024 * 1024)
2015-12-23 01:29:42 -08:00
# define VERTEXCACHE_NAME_CACHE_MAX_AGE 120
2013-08-01 00:13:58 +02:00
2014-09-07 17:08:05 -07:00
enum { VAI_KILL_AGE = 120 , VAI_UNRELIABLE_KILL_AGE = 240 , VAI_UNRELIABLE_KILL_MAX = 4 } ;
2014-03-23 15:34:04 +01:00
2017-11-19 12:25:57 +01:00
DrawEngineGLES : : DrawEngineGLES ( Draw : : DrawContext * draw ) : vai_ ( 256 ) , draw_ ( draw ) , inputLayoutMap_ ( 16 ) {
render_ = ( GLRenderManager * ) draw_ - > GetNativeObject ( Draw : : NativeObject : : RENDER_MANAGER ) ;
2017-01-25 19:44:17 +01:00
decOptions_ . expandAllWeightsToFloat = false ;
decOptions_ . expand8BitNormalsToFloat = false ;
2013-08-01 00:13:58 +02:00
decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL ;
2015-12-23 01:29:42 -08:00
bufferDecimationCounter_ = VERTEXCACHE_NAME_DECIMATION_INTERVAL ;
2013-01-29 00:48:13 +01:00
// Allocate nicely aligned memory. Maybe graphics drivers will
// appreciate it.
// All this is a LOT of memory, need to see if we can cut down somehow.
2016-08-28 12:28:17 +02:00
decoded = ( u8 * ) AllocateMemoryPages ( DECODED_VERTEX_BUFFER_SIZE , MEM_PROT_READ | MEM_PROT_WRITE ) ;
decIndex = ( u16 * ) AllocateMemoryPages ( DECODED_INDEX_BUFFER_SIZE , MEM_PROT_READ | MEM_PROT_WRITE ) ;
2013-09-24 11:14:04 +02:00
2012-12-25 13:47:59 +01:00
indexGen . Setup ( decIndex ) ;
2013-11-03 15:27:12 +01:00
2013-01-10 12:51:18 +01:00
InitDeviceObjects ( ) ;
2017-01-09 03:37:21 +09:00
2018-07-11 01:09:20 +09:00
tessDataTransferGLES = new TessellationDataTransferGLES ( render_ ) ;
tessDataTransfer = tessDataTransferGLES ;
2012-12-25 13:47:59 +01:00
}
2012-11-01 16:19:01 +01:00
2016-04-10 10:21:48 +02:00
DrawEngineGLES : : ~ DrawEngineGLES ( ) {
2013-01-10 12:51:18 +01:00
DestroyDeviceObjects ( ) ;
2013-01-29 00:48:13 +01:00
FreeMemoryPages ( decoded , DECODED_VERTEX_BUFFER_SIZE ) ;
FreeMemoryPages ( decIndex , DECODED_INDEX_BUFFER_SIZE ) ;
2013-09-24 11:14:04 +02:00
2018-07-13 18:35:44 +09:00
delete tessDataTransferGLES ;
2013-01-10 12:51:18 +01:00
}
2017-12-09 23:58:08 +01:00
void DrawEngineGLES : : DeviceLost ( ) {
DestroyDeviceObjects ( ) ;
}
2018-05-27 22:19:03 +02:00
void DrawEngineGLES : : DeviceRestore ( Draw : : DrawContext * draw ) {
draw_ = draw ;
2018-05-30 19:29:26 +02:00
render_ = ( GLRenderManager * ) draw_ - > GetNativeObject ( Draw : : NativeObject : : RENDER_MANAGER ) ;
2017-12-09 23:58:08 +01:00
InitDeviceObjects ( ) ;
}
2016-04-10 10:21:48 +02:00
void DrawEngineGLES : : InitDeviceObjects ( ) {
2018-05-27 21:54:07 +02:00
_assert_msg_ ( G3D , render_ ! = nullptr , " Render manager must be set " ) ;
2017-11-19 12:25:57 +01:00
for ( int i = 0 ; i < GLRenderManager : : MAX_INFLIGHT_FRAMES ; i + + ) {
2018-04-05 17:53:03 +02:00
frameData_ [ i ] . pushVertex = render_ - > CreatePushBuffer ( i , GL_ARRAY_BUFFER , 1024 * 1024 ) ;
frameData_ [ i ] . pushIndex = render_ - > CreatePushBuffer ( i , GL_ELEMENT_ARRAY_BUFFER , 256 * 1024 ) ;
2017-11-19 12:25:57 +01:00
}
int vertexSize = sizeof ( TransformedVertex ) ;
std : : vector < GLRInputLayout : : Entry > entries ;
entries . push_back ( { ATTR_POSITION , 4 , GL_FLOAT , GL_FALSE , vertexSize , 0 } ) ;
entries . push_back ( { ATTR_TEXCOORD , 3 , GL_FLOAT , GL_FALSE , vertexSize , offsetof ( TransformedVertex , u ) } ) ;
entries . push_back ( { ATTR_COLOR0 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , vertexSize , offsetof ( TransformedVertex , color0 ) } ) ;
entries . push_back ( { ATTR_COLOR1 , 3 , GL_UNSIGNED_BYTE , GL_TRUE , vertexSize , offsetof ( TransformedVertex , color1 ) } ) ;
softwareInputLayout_ = render_ - > CreateInputLayout ( entries ) ;
2013-01-10 12:51:18 +01:00
}
2016-04-10 10:21:48 +02:00
void DrawEngineGLES : : DestroyDeviceObjects ( ) {
2018-01-19 23:03:08 -08:00
// Beware: this could be called twice in a row, sometimes.
2017-11-19 12:25:57 +01:00
for ( int i = 0 ; i < GLRenderManager : : MAX_INFLIGHT_FRAMES ; i + + ) {
2018-01-19 23:03:08 -08:00
if ( ! frameData_ [ i ] . pushVertex & & ! frameData_ [ i ] . pushIndex )
continue ;
2018-05-27 21:54:07 +02:00
if ( frameData_ [ i ] . pushVertex )
render_ - > DeletePushBuffer ( frameData_ [ i ] . pushVertex ) ;
if ( frameData_ [ i ] . pushIndex )
render_ - > DeletePushBuffer ( frameData_ [ i ] . pushIndex ) ;
2018-01-19 23:03:08 -08:00
frameData_ [ i ] . pushVertex = nullptr ;
frameData_ [ i ] . pushIndex = nullptr ;
2017-11-19 12:25:57 +01:00
}
2015-12-23 18:17:22 -08:00
ClearTrackedVertexArrays ( ) ;
2017-11-19 12:25:57 +01:00
2018-01-19 23:03:08 -08:00
if ( softwareInputLayout_ )
render_ - > DeleteInputLayout ( softwareInputLayout_ ) ;
softwareInputLayout_ = nullptr ;
2018-02-07 16:54:39 +01:00
ClearInputLayoutMap ( ) ;
2017-11-19 12:25:57 +01:00
}
void DrawEngineGLES : : ClearInputLayoutMap ( ) {
inputLayoutMap_ . Iterate ( [ & ] ( const uint32_t & key , GLRInputLayout * il ) {
render_ - > DeleteInputLayout ( il ) ;
} ) ;
inputLayoutMap_ . Clear ( ) ;
}
void DrawEngineGLES : : BeginFrame ( ) {
FrameData & frameData = frameData_ [ render_ - > GetCurFrame ( ) ] ;
2018-04-05 17:34:32 +02:00
render_ - > BeginPushBuffer ( frameData . pushIndex ) ;
render_ - > BeginPushBuffer ( frameData . pushVertex ) ;
2017-11-19 12:25:57 +01:00
}
void DrawEngineGLES : : EndFrame ( ) {
FrameData & frameData = frameData_ [ render_ - > GetCurFrame ( ) ] ;
2018-04-05 17:34:32 +02:00
render_ - > EndPushBuffer ( frameData . pushIndex ) ;
render_ - > EndPushBuffer ( frameData . pushVertex ) ;
2018-07-11 01:09:20 +09:00
tessDataTransferGLES - > EndFrame ( ) ;
2013-01-10 12:51:18 +01:00
}
2012-12-20 14:10:42 +01:00
struct GlTypeInfo {
2013-02-04 23:09:01 +01:00
u16 type ;
u8 count ;
u8 normalized ;
2012-12-20 14:10:42 +01:00
} ;
2012-12-19 18:35:37 +01:00
2013-02-04 23:09:01 +01:00
static const GlTypeInfo GLComp [ ] = {
2012-12-20 14:10:42 +01:00
{ 0 } , // DEC_NONE,
{ GL_FLOAT , 1 , GL_FALSE } , // DEC_FLOAT_1,
{ GL_FLOAT , 2 , GL_FALSE } , // DEC_FLOAT_2,
{ GL_FLOAT , 3 , GL_FALSE } , // DEC_FLOAT_3,
{ GL_FLOAT , 4 , GL_FALSE } , // DEC_FLOAT_4,
2013-01-22 21:57:47 +01:00
{ GL_BYTE , 4 , GL_TRUE } , // DEC_S8_3,
{ GL_SHORT , 4 , GL_TRUE } , // DEC_S16_3,
2013-02-04 23:09:01 +01:00
{ GL_UNSIGNED_BYTE , 1 , GL_TRUE } , // DEC_U8_1,
{ GL_UNSIGNED_BYTE , 2 , GL_TRUE } , // DEC_U8_2,
2013-01-29 00:48:13 +01:00
{ GL_UNSIGNED_BYTE , 3 , GL_TRUE } , // DEC_U8_3,
2013-02-04 23:09:01 +01:00
{ GL_UNSIGNED_BYTE , 4 , GL_TRUE } , // DEC_U8_4,
2013-02-05 18:00:21 +01:00
{ GL_UNSIGNED_SHORT , 1 , GL_TRUE } , // DEC_U16_1,
2013-02-05 01:37:00 +01:00
{ GL_UNSIGNED_SHORT , 2 , GL_TRUE } , // DEC_U16_2,
2013-02-05 18:00:21 +01:00
{ GL_UNSIGNED_SHORT , 3 , GL_TRUE } , // DEC_U16_3,
{ GL_UNSIGNED_SHORT , 4 , GL_TRUE } , // DEC_U16_4,
2012-12-20 14:10:42 +01:00
} ;
2012-12-19 18:35:37 +01:00
2017-11-19 12:25:57 +01:00
static inline void VertexAttribSetup ( int attrib , int fmt , int stride , int offset , std : : vector < GLRInputLayout : : Entry > & entries ) {
2016-03-05 13:12:24 -08:00
if ( fmt ) {
2012-12-20 14:10:42 +01:00
const GlTypeInfo & type = GLComp [ fmt ] ;
2017-11-19 12:25:57 +01:00
GLRInputLayout : : Entry entry ;
entry . offset = offset ;
entry . location = attrib ;
entry . normalized = type . normalized ;
entry . type = type . type ;
entry . stride = stride ;
entry . count = type . count ;
entries . push_back ( entry ) ;
2012-12-05 10:45:28 +07:00
}
2012-12-20 14:10:42 +01:00
}
2012-12-05 10:45:28 +07:00
2012-12-20 14:10:42 +01:00
// TODO: Use VBO and get rid of the vertexData pointers - with that, we will supply only offsets
2017-11-19 12:25:57 +01:00
GLRInputLayout * DrawEngineGLES : : SetupDecFmtForDraw ( LinkedShader * program , const DecVtxFormat & decFmt ) {
uint32_t key = decFmt . id ;
GLRInputLayout * inputLayout = inputLayoutMap_ . Get ( key ) ;
if ( inputLayout ) {
return inputLayout ;
}
std : : vector < GLRInputLayout : : Entry > entries ;
2018-04-10 11:21:56 +02:00
VertexAttribSetup ( ATTR_W1 , decFmt . w0fmt , decFmt . stride , decFmt . w0off , entries ) ;
VertexAttribSetup ( ATTR_W2 , decFmt . w1fmt , decFmt . stride , decFmt . w1off , entries ) ;
2017-11-19 12:25:57 +01:00
VertexAttribSetup ( ATTR_TEXCOORD , decFmt . uvfmt , decFmt . stride , decFmt . uvoff , entries ) ;
VertexAttribSetup ( ATTR_COLOR0 , decFmt . c0fmt , decFmt . stride , decFmt . c0off , entries ) ;
VertexAttribSetup ( ATTR_COLOR1 , decFmt . c1fmt , decFmt . stride , decFmt . c1off , entries ) ;
VertexAttribSetup ( ATTR_NORMAL , decFmt . nrmfmt , decFmt . stride , decFmt . nrmoff , entries ) ;
VertexAttribSetup ( ATTR_POSITION , decFmt . posfmt , decFmt . stride , decFmt . posoff , entries ) ;
inputLayout = render_ - > CreateInputLayout ( entries ) ;
inputLayoutMap_ . Insert ( key , inputLayout ) ;
return inputLayout ;
2012-12-20 14:10:42 +01:00
}
2017-11-19 12:25:57 +01:00
void DrawEngineGLES : : DecodeVertsToPushBuffer ( GLPushBuffer * push , uint32_t * bindOffset , GLRBuffer * * buf ) {
u8 * dest = decoded ;
// Figure out how much pushbuffer space we need to allocate.
if ( push ) {
int vertsToDecode = ComputeNumVertsToDecode ( ) ;
dest = ( u8 * ) push - > Push ( vertsToDecode * dec_ - > GetDecVtxFmt ( ) . stride , bindOffset , buf ) ;
}
DecodeVerts ( dest ) ;
}
2016-04-10 10:21:48 +02:00
void DrawEngineGLES : : MarkUnreliable ( VertexArrayInfo * vai ) {
2014-09-07 17:28:12 -07:00
vai - > status = VertexArrayInfo : : VAI_UNRELIABLE ;
if ( vai - > vbo ) {
2017-12-12 14:07:52 +01:00
render_ - > DeleteBuffer ( vai - > vbo ) ;
2014-09-07 17:28:12 -07:00
vai - > vbo = 0 ;
}
if ( vai - > ebo ) {
2017-12-12 14:07:52 +01:00
render_ - > DeleteBuffer ( vai - > ebo ) ;
2014-09-07 17:28:12 -07:00
vai - > ebo = 0 ;
}
}
2016-04-10 10:21:48 +02:00
void DrawEngineGLES : : ClearTrackedVertexArrays ( ) {
2017-08-20 11:30:19 +02:00
vai_ . Iterate ( [ & ] ( uint32_t hash , VertexArrayInfo * vai ) {
FreeVertexArray ( vai ) ;
delete vai ;
} ) ;
vai_ . Clear ( ) ;
2013-01-19 17:05:08 +01:00
}
2016-04-10 10:21:48 +02:00
void DrawEngineGLES : : DecimateTrackedVertexArrays ( ) {
2013-08-01 00:13:58 +02:00
if ( - - decimationCounter_ < = 0 ) {
decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL ;
} else {
return ;
}
2014-09-14 13:50:57 -07:00
const int threshold = gpuStats . numFlips - VAI_KILL_AGE ;
const int unreliableThreshold = gpuStats . numFlips - VAI_UNRELIABLE_KILL_AGE ;
2014-09-07 17:08:05 -07:00
int unreliableLeft = VAI_UNRELIABLE_KILL_MAX ;
2017-08-20 11:30:19 +02:00
vai_ . Iterate ( [ & ] ( uint32_t hash , VertexArrayInfo * vai ) {
2014-09-07 17:08:05 -07:00
bool kill ;
2017-08-20 11:30:19 +02:00
if ( vai - > status = = VertexArrayInfo : : VAI_UNRELIABLE ) {
2014-09-07 17:08:05 -07:00
// We limit killing unreliable so we don't rehash too often.
2017-08-20 11:30:19 +02:00
kill = vai - > lastFrame < unreliableThreshold & & - - unreliableLeft > = 0 ;
2014-09-07 17:08:05 -07:00
} else {
2017-08-20 11:30:19 +02:00
kill = vai - > lastFrame < threshold ;
2014-09-07 17:08:05 -07:00
}
if ( kill ) {
2017-08-20 11:30:19 +02:00
FreeVertexArray ( vai ) ;
delete vai ;
vai_ . Remove ( hash ) ;
2013-12-09 13:45:17 +01:00
}
2017-08-20 11:30:19 +02:00
} ) ;
2017-08-20 13:20:16 +02:00
vai_ . Maintain ( ) ;
2012-12-21 19:16:17 +01:00
}
2016-04-10 10:21:48 +02:00
void DrawEngineGLES : : FreeVertexArray ( VertexArrayInfo * vai ) {
2015-12-23 16:57:24 -08:00
if ( vai - > vbo ) {
2017-12-12 14:07:52 +01:00
render_ - > DeleteBuffer ( vai - > vbo ) ;
vai - > vbo = nullptr ;
2015-12-23 16:57:24 -08:00
}
if ( vai - > ebo ) {
2017-12-12 14:07:52 +01:00
render_ - > DeleteBuffer ( vai - > ebo ) ;
vai - > ebo = nullptr ;
2015-12-23 16:57:24 -08:00
}
}
2016-04-10 10:21:48 +02:00
void DrawEngineGLES : : DoFlush ( ) {
2015-07-03 12:05:08 -07:00
PROFILE_THIS_SCOPE ( " flush " ) ;
2017-03-03 14:15:27 +01:00
2017-11-19 12:25:57 +01:00
FrameData & frameData = frameData_ [ render_ - > GetCurFrame ( ) ] ;
2013-01-19 17:05:08 +01:00
gpuStats . numFlushes + + ;
2013-02-24 10:38:30 -08:00
gpuStats . numTrackedVertexArrays = ( int ) vai_ . size ( ) ;
2012-12-19 18:35:37 +01:00
2017-12-14 17:50:40 +01:00
bool textureNeedsApply = false ;
if ( gstate_c . IsDirty ( DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS ) & & ! gstate . isModeClear ( ) & & gstate . isTextureMapEnabled ( ) ) {
textureCache_ - > SetTexture ( ) ;
gstate_c . Clean ( DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS ) ;
textureNeedsApply = true ;
2018-04-22 11:16:33 -07:00
} else if ( gstate . getTextureAddress ( 0 ) = = ( ( gstate . getFrameBufRawAddress ( ) | 0x04000000 ) & 0x3FFFFFFF ) ) {
2018-11-11 10:54:28 +01:00
// This catches the case of clearing a texture. (#10957)
2018-04-22 11:16:33 -07:00
gstate_c . Dirty ( DIRTY_TEXTURE_IMAGE ) ;
2017-12-14 17:50:40 +01:00
}
2013-08-25 19:51:06 +02:00
GEPrimitiveType prim = prevPrim_ ;
2012-12-20 14:10:42 +01:00
2017-12-02 09:07:27 -08:00
VShaderID vsid ;
2016-01-17 20:29:34 +01:00
Shader * vshader = shaderManager_ - > ApplyVertexShader ( prim , lastVType_ , & vsid ) ;
2012-12-20 14:10:42 +01:00
2017-11-19 12:25:57 +01:00
GLRBuffer * vertexBuffer = nullptr ;
GLRBuffer * indexBuffer = nullptr ;
uint32_t vertexBufferOffset = 0 ;
uint32_t indexBufferOffset = 0 ;
2014-03-24 10:55:07 +01:00
if ( vshader - > UseHWTransform ( ) ) {
2013-01-19 19:22:15 +01:00
int vertexCount = 0 ;
2013-01-20 21:52:54 +01:00
bool useElements = true ;
2013-11-10 13:18:52 +01:00
2013-01-20 22:48:29 +01:00
// Cannot cache vertex data with morph enabled.
2013-11-10 13:18:52 +01:00
bool useCache = g_Config . bVertexCache & & ! ( lastVType_ & GE_VTYPE_MORPHCOUNT_MASK ) ;
2018-04-10 11:50:24 +02:00
// Also avoid caching when software skinning.
2018-04-10 12:22:02 +02:00
if ( g_Config . bSoftwareSkinning & & ( lastVType_ & GE_VTYPE_WEIGHT_MASK ) )
2013-11-10 13:18:52 +01:00
useCache = false ;
2017-11-19 12:25:57 +01:00
// TEMPORARY
useCache = false ;
2013-11-10 13:18:52 +01:00
if ( useCache ) {
2017-02-04 11:15:47 +01:00
u32 id = dcid_ ^ gstate . getUVGenMode ( ) ; // This can have an effect on which UV decoder we need to use! And hence what the decoded data will look like. See #9263
2017-08-20 11:30:19 +02:00
VertexArrayInfo * vai = vai_ . Get ( id ) ;
if ( ! vai ) {
2013-01-20 13:15:46 +01:00
vai = new VertexArrayInfo ( ) ;
2017-08-20 11:30:19 +02:00
vai_ . Insert ( id , vai ) ;
2013-01-20 13:15:46 +01:00
}
2013-01-19 19:22:15 +01:00
2013-01-20 21:52:54 +01:00
switch ( vai - > status ) {
2013-01-20 13:15:46 +01:00
case VertexArrayInfo : : VAI_NEW :
{
// Haven't seen this one before.
2014-10-26 17:49:24 -07:00
ReliableHashType dataHash = ComputeHash ( ) ;
2013-01-20 13:15:46 +01:00
vai - > hash = dataHash ;
2014-09-07 17:29:28 -07:00
vai - > minihash = ComputeMiniHash ( ) ;
2013-01-20 13:15:46 +01:00
vai - > status = VertexArrayInfo : : VAI_HASHING ;
2013-02-11 23:41:31 -08:00
vai - > drawsUntilNextFullHash = 0 ;
2017-11-19 12:38:52 +01:00
DecodeVerts ( decoded ) ; // writes to indexGen
2013-07-22 19:10:19 +02:00
vai - > numVerts = indexGen . VertexCount ( ) ;
vai - > prim = indexGen . Prim ( ) ;
2013-10-08 22:59:40 +02:00
vai - > maxIndex = indexGen . MaxIndex ( ) ;
2014-03-24 11:19:11 +01:00
vai - > flags = gstate_c . vertexFullAlpha ? VAI_FLAG_VERTEXFULLALPHA : 0 ;
2013-01-20 13:15:46 +01:00
goto rotateVBO ;
}
2013-01-19 19:22:15 +01:00
2013-01-20 13:15:46 +01:00
// Hashing - still gaining confidence about the buffer.
// But if we get this far it's likely to be worth creating a vertex buffer.
case VertexArrayInfo : : VAI_HASHING :
{
vai - > numDraws + + ;
2013-08-07 22:32:04 +02:00
if ( vai - > lastFrame ! = gpuStats . numFlips ) {
2013-02-10 12:27:43 -08:00
vai - > numFrames + + ;
}
2013-02-11 23:41:31 -08:00
if ( vai - > drawsUntilNextFullHash = = 0 ) {
2014-09-07 17:34:29 -07:00
// Let's try to skip a full hash if mini would fail.
const u32 newMiniHash = ComputeMiniHash ( ) ;
2014-10-26 17:49:24 -07:00
ReliableHashType newHash = vai - > hash ;
2014-09-07 17:34:29 -07:00
if ( newMiniHash = = vai - > minihash ) {
newHash = ComputeHash ( ) ;
}
if ( newMiniHash ! = vai - > minihash | | newHash ! = vai - > hash ) {
2014-09-07 17:28:12 -07:00
MarkUnreliable ( vai ) ;
2017-11-19 12:38:52 +01:00
DecodeVerts ( decoded ) ;
2013-02-06 00:42:06 +01:00
goto rotateVBO ;
2013-01-20 21:52:54 +01:00
}
2014-09-07 17:36:19 -07:00
if ( vai - > numVerts > 64 ) {
// exponential backoff up to 16 draws, then every 32
vai - > drawsUntilNextFullHash = std : : min ( 32 , vai - > numFrames ) ;
2013-02-12 00:02:53 -08:00
} else {
// Lower numbers seem much more likely to change.
2013-02-12 00:17:12 -08:00
vai - > drawsUntilNextFullHash = 0 ;
2013-02-12 00:02:53 -08:00
}
// TODO: tweak
//if (vai->numFrames > 1000) {
// vai->status = VertexArrayInfo::VAI_RELIABLE;
//}
2013-02-06 00:42:06 +01:00
} else {
2013-02-11 23:41:31 -08:00
vai - > drawsUntilNextFullHash - - ;
2014-09-07 17:29:28 -07:00
u32 newMiniHash = ComputeMiniHash ( ) ;
if ( newMiniHash ! = vai - > minihash ) {
MarkUnreliable ( vai ) ;
2017-11-19 12:38:52 +01:00
DecodeVerts ( decoded ) ;
2014-09-07 17:29:28 -07:00
goto rotateVBO ;
}
2013-01-19 19:22:15 +01:00
}
2013-02-06 00:42:06 +01:00
2013-01-20 13:15:46 +01:00
if ( vai - > vbo = = 0 ) {
2017-11-19 12:38:52 +01:00
DecodeVerts ( decoded ) ;
2013-01-20 13:15:46 +01:00
vai - > numVerts = indexGen . VertexCount ( ) ;
vai - > prim = indexGen . Prim ( ) ;
2013-10-08 22:59:40 +02:00
vai - > maxIndex = indexGen . MaxIndex ( ) ;
2014-03-25 08:19:14 -07:00
vai - > flags = gstate_c . vertexFullAlpha ? VAI_FLAG_VERTEXFULLALPHA : 0 ;
2013-01-20 22:42:11 +01:00
useElements = ! indexGen . SeenOnlyPurePrims ( ) ;
2013-04-20 23:35:53 +02:00
if ( ! useElements & & indexGen . PureCount ( ) ) {
vai - > numVerts = indexGen . PureCount ( ) ;
}
2013-12-09 13:45:17 +01:00
2015-09-13 14:52:10 -07:00
_dbg_assert_msg_ ( G3D , gstate_c . vertBounds . minV > = gstate_c . vertBounds . maxV , " Should not have checked UVs when caching. " ) ;
2015-09-13 11:09:21 -07:00
2015-12-22 23:06:56 -08:00
size_t vsz = dec_ - > GetDecVtxFmt ( ) . stride * indexGen . MaxIndex ( ) ;
2017-12-12 14:07:52 +01:00
vai - > vbo = render_ - > CreateBuffer ( GL_ARRAY_BUFFER , vsz , GL_STATIC_DRAW ) ;
render_ - > BufferSubdata ( vai - > vbo , 0 , vsz , decoded ) ;
2013-01-20 13:15:46 +01:00
// If there's only been one primitive type, and it's either TRIANGLES, LINES or POINTS,
// there is no need for the index buffer we built. We can then use glDrawArrays instead
// for a very minor speed boost.
2013-01-20 22:42:11 +01:00
if ( useElements ) {
2015-12-22 23:06:56 -08:00
size_t esz = sizeof ( short ) * indexGen . VertexCount ( ) ;
2017-12-12 14:07:52 +01:00
vai - > ebo = render_ - > CreateBuffer ( GL_ARRAY_BUFFER , esz , GL_STATIC_DRAW ) ;
render_ - > BufferSubdata ( vai - > ebo , 0 , esz , ( uint8_t * ) decIndex , false ) ;
2013-01-20 21:52:54 +01:00
} else {
vai - > ebo = 0 ;
2017-12-12 14:07:52 +01:00
render_ - > BindIndexBuffer ( vai - > ebo ) ;
2013-01-20 13:15:46 +01:00
}
} else {
2013-02-06 00:42:06 +01:00
gpuStats . numCachedDrawCalls + + ;
2013-01-20 22:42:11 +01:00
useElements = vai - > ebo ? true : false ;
2013-01-25 00:36:59 +01:00
gpuStats . numCachedVertsDrawn + = vai - > numVerts ;
2014-03-25 08:19:14 -07:00
gstate_c . vertexFullAlpha = vai - > flags & VAI_FLAG_VERTEXFULLALPHA ;
2013-01-19 19:22:15 +01:00
}
2017-12-12 14:07:52 +01:00
vertexBuffer = vai - > vbo ;
indexBuffer = vai - > ebo ;
2013-01-20 13:15:46 +01:00
vertexCount = vai - > numVerts ;
2013-08-25 19:51:06 +02:00
prim = static_cast < GEPrimitiveType > ( vai - > prim ) ;
2013-01-20 13:15:46 +01:00
break ;
2013-01-19 19:22:15 +01:00
}
2013-01-20 13:15:46 +01:00
// Reliable - we don't even bother hashing anymore. Right now we don't go here until after a very long time.
case VertexArrayInfo : : VAI_RELIABLE :
{
vai - > numDraws + + ;
2013-08-07 22:32:04 +02:00
if ( vai - > lastFrame ! = gpuStats . numFlips ) {
2013-02-10 12:27:43 -08:00
vai - > numFrames + + ;
}
2013-01-20 13:15:46 +01:00
gpuStats . numCachedDrawCalls + + ;
2013-01-25 00:36:59 +01:00
gpuStats . numCachedVertsDrawn + = vai - > numVerts ;
2017-12-12 14:07:52 +01:00
vertexBuffer = vai - > vbo ;
indexBuffer = vai - > ebo ;
2013-01-20 13:15:46 +01:00
vertexCount = vai - > numVerts ;
2013-08-25 19:51:06 +02:00
prim = static_cast < GEPrimitiveType > ( vai - > prim ) ;
2014-03-24 11:19:11 +01:00
gstate_c . vertexFullAlpha = vai - > flags & VAI_FLAG_VERTEXFULLALPHA ;
2013-01-20 13:15:46 +01:00
break ;
}
case VertexArrayInfo : : VAI_UNRELIABLE :
{
vai - > numDraws + + ;
2013-08-07 22:32:04 +02:00
if ( vai - > lastFrame ! = gpuStats . numFlips ) {
2013-02-10 12:27:43 -08:00
vai - > numFrames + + ;
}
2017-11-19 12:38:52 +01:00
DecodeVerts ( decoded ) ;
2013-01-20 13:15:46 +01:00
goto rotateVBO ;
}
}
2013-02-11 23:29:49 -08:00
2013-08-07 22:32:04 +02:00
vai - > lastFrame = gpuStats . numFlips ;
2013-01-20 13:15:46 +01:00
} else {
2018-04-10 12:22:02 +02:00
if ( g_Config . bSoftwareSkinning & & ( lastVType_ & GE_VTYPE_WEIGHT_MASK ) ) {
2018-04-10 11:50:24 +02:00
// If software skinning, we've already predecoded into "decoded". So push that content.
2017-12-14 16:36:05 +01:00
size_t size = decodedVerts_ * dec_ - > GetDecVtxFmt ( ) . stride ;
u8 * dest = ( u8 * ) frameData . pushVertex - > Push ( size , & vertexBufferOffset , & vertexBuffer ) ;
memcpy ( dest , decoded , size ) ;
} else {
// Decode directly into the pushbuffer
DecodeVertsToPushBuffer ( frameData . pushVertex , & vertexBufferOffset , & vertexBuffer ) ;
}
2013-12-09 13:45:17 +01:00
2013-01-19 19:22:15 +01:00
rotateVBO :
2013-01-25 00:36:59 +01:00
gpuStats . numUncachedVertsDrawn + = indexGen . VertexCount ( ) ;
2013-01-20 21:52:54 +01:00
useElements = ! indexGen . SeenOnlyPurePrims ( ) ;
2013-01-28 19:04:12 +01:00
vertexCount = indexGen . VertexCount ( ) ;
2013-04-20 23:35:53 +02:00
if ( ! useElements & & indexGen . PureCount ( ) ) {
vertexCount = indexGen . PureCount ( ) ;
}
2013-01-20 21:52:54 +01:00
prim = indexGen . Prim ( ) ;
2013-01-19 19:22:15 +01:00
}
2013-12-09 13:45:17 +01:00
2013-11-14 11:01:31 +01:00
VERBOSE_LOG ( G3D , " Flush prim %i! %i verts in one go " , prim , vertexCount ) ;
2014-03-24 17:33:20 +01:00
bool hasColor = ( lastVType_ & GE_VTYPE_COL_MASK ) ! = GE_VTYPE_COL_NONE ;
if ( gstate . isModeThrough ( ) ) {
gstate_c . vertexFullAlpha = gstate_c . vertexFullAlpha & & ( hasColor | | gstate . getMaterialAmbientA ( ) = = 255 ) ;
} else {
gstate_c . vertexFullAlpha = gstate_c . vertexFullAlpha & & ( ( hasColor & & ( gstate . materialupdate & 1 ) ) | | gstate . getMaterialAmbientA ( ) = = 255 ) & & ( ! gstate . isLightingEnabled ( ) | | gstate . getAmbientA ( ) = = 255 ) ;
}
2013-01-19 19:22:15 +01:00
2017-12-14 17:50:40 +01:00
if ( textureNeedsApply )
textureCache_ - > ApplyTexture ( ) ;
// Need to ApplyDrawState after ApplyTexture because depal can launch a render pass and that wrecks the state.
ApplyDrawState ( prim ) ;
2017-12-12 15:04:46 +01:00
ApplyDrawStateLate ( false , 0 ) ;
2017-11-19 18:22:46 +01:00
2016-01-17 20:29:34 +01:00
LinkedShader * program = shaderManager_ - > ApplyFragmentShader ( vsid , vshader , lastVType_ , prim ) ;
2017-11-19 12:25:57 +01:00
GLRInputLayout * inputLayout = SetupDecFmtForDraw ( program , dec_ - > GetDecVtxFmt ( ) ) ;
2017-12-19 12:25:13 +01:00
render_ - > BindVertexBuffer ( inputLayout , vertexBuffer , vertexBufferOffset ) ;
2013-01-20 21:52:54 +01:00
if ( useElements ) {
2017-11-19 12:25:57 +01:00
if ( ! indexBuffer ) {
indexBufferOffset = ( uint32_t ) frameData . pushIndex - > Push ( decIndex , sizeof ( uint16_t ) * indexGen . VertexCount ( ) , & indexBuffer ) ;
render_ - > BindIndexBuffer ( indexBuffer ) ;
}
2018-09-22 19:20:30 +09:00
render_ - > DrawIndexed ( glprim [ prim ] , vertexCount , GL_UNSIGNED_SHORT , ( GLvoid * ) ( intptr_t ) indexBufferOffset ) ;
2013-01-20 21:52:54 +01:00
} else {
2017-11-19 12:25:57 +01:00
render_ - > Draw ( glprim [ prim ] , 0 , vertexCount ) ;
2012-12-26 08:54:33 +01:00
}
2012-12-20 14:10:42 +01:00
} else {
2017-11-19 12:38:52 +01:00
DecodeVerts ( decoded ) ;
2014-03-24 17:33:20 +01:00
bool hasColor = ( lastVType_ & GE_VTYPE_COL_MASK ) ! = GE_VTYPE_COL_NONE ;
if ( gstate . isModeThrough ( ) ) {
gstate_c . vertexFullAlpha = gstate_c . vertexFullAlpha & & ( hasColor | | gstate . getMaterialAmbientA ( ) = = 255 ) ;
} else {
gstate_c . vertexFullAlpha = gstate_c . vertexFullAlpha & & ( ( hasColor & & ( gstate . materialupdate & 1 ) ) | | gstate . getMaterialAmbientA ( ) = = 255 ) & & ( ! gstate . isLightingEnabled ( ) | | gstate . getAmbientA ( ) = = 255 ) ;
}
2014-03-24 11:19:11 +01:00
2013-01-25 00:36:59 +01:00
gpuStats . numUncachedVertsDrawn + = indexGen . VertexCount ( ) ;
2013-01-19 19:22:15 +01:00
prim = indexGen . Prim ( ) ;
2013-04-21 19:28:24 +02:00
// Undo the strip optimization, not supported by the SW code yet.
if ( prim = = GE_PRIM_TRIANGLE_STRIP )
prim = GE_PRIM_TRIANGLES ;
2013-01-19 19:22:15 +01:00
2014-09-13 13:03:37 +02:00
TransformedVertex * drawBuffer = NULL ;
int numTrans ;
bool drawIndexed = false ;
u16 * inds = decIndex ;
2017-12-02 09:58:13 +01:00
SoftwareTransformResult result { } ;
2016-03-12 13:37:08 -08:00
// TODO: Keep this static? Faster than repopulating?
2017-12-02 09:58:13 +01:00
SoftwareTransformParams params { } ;
2016-03-12 13:37:08 -08:00
params . decoded = decoded ;
params . transformed = transformed ;
params . transformedExpanded = transformedExpanded ;
params . fbman = framebufferManager_ ;
params . texCache = textureCache_ ;
2017-12-02 09:58:13 +01:00
params . allowClear = true ;
2016-03-12 13:37:08 -08:00
params . allowSeparateAlphaClear = true ;
2018-04-28 16:32:09 -07:00
params . provokeFlatFirst = false ;
2016-03-12 13:37:08 -08:00
2015-01-15 23:58:07 +01:00
int maxIndex = indexGen . MaxIndex ( ) ;
2017-11-10 15:59:36 +01:00
int vertexCount = indexGen . VertexCount ( ) ;
// TODO: Split up into multiple draw calls for GLES 2.0 where you can't guarantee support for more than 0x10000 verts.
# if defined(MOBILE_DEVICE)
if ( vertexCount > 0x10000 / 3 )
vertexCount = 0x10000 / 3 ;
# endif
2014-09-13 13:03:37 +02:00
SoftwareTransform (
2017-11-10 15:59:36 +01:00
prim , vertexCount ,
2015-01-15 12:26:35 -08:00
dec_ - > VertexType ( ) , inds , GE_VTYPE_IDX_16BIT , dec_ - > GetDecVtxFmt ( ) ,
2016-03-12 13:37:08 -08:00
maxIndex , drawBuffer , numTrans , drawIndexed , & params , & result ) ;
2017-12-14 17:50:40 +01:00
if ( textureNeedsApply )
textureCache_ - > ApplyTexture ( ) ;
ApplyDrawState ( prim ) ;
2017-12-12 15:04:46 +01:00
ApplyDrawStateLate ( result . setStencil , result . stencilValue ) ;
2015-09-25 19:08:48 +02:00
2016-01-17 20:29:34 +01:00
LinkedShader * program = shaderManager_ - > ApplyFragmentShader ( vsid , vshader , lastVType_ , prim ) ;
2015-09-13 06:53:25 -07:00
2014-09-13 13:03:37 +02:00
if ( result . action = = SW_DRAW_PRIMITIVES ) {
const int vertexSize = sizeof ( transformed [ 0 ] ) ;
bool doTextureProjection = gstate . getUVGenMode ( ) = = GE_TEXMAP_TEXTURE_MATRIX ;
2015-12-13 22:48:21 -08:00
2014-09-13 13:03:37 +02:00
if ( drawIndexed ) {
2017-11-19 12:25:57 +01:00
vertexBufferOffset = ( uint32_t ) frameData . pushVertex - > Push ( drawBuffer , maxIndex * sizeof ( TransformedVertex ) , & vertexBuffer ) ;
2017-12-14 14:53:27 +01:00
indexBufferOffset = ( uint32_t ) frameData . pushIndex - > Push ( inds , sizeof ( uint16_t ) * numTrans , & indexBuffer ) ;
2017-12-19 12:25:13 +01:00
render_ - > BindVertexBuffer ( softwareInputLayout_ , vertexBuffer , vertexBufferOffset ) ;
2017-11-19 18:22:46 +01:00
render_ - > BindIndexBuffer ( indexBuffer ) ;
render_ - > DrawIndexed ( glprim [ prim ] , numTrans , GL_UNSIGNED_SHORT , ( void * ) ( intptr_t ) indexBufferOffset ) ;
2014-09-13 13:03:37 +02:00
} else {
2017-11-19 12:25:57 +01:00
vertexBufferOffset = ( uint32_t ) frameData . pushVertex - > Push ( drawBuffer , numTrans * sizeof ( TransformedVertex ) , & vertexBuffer ) ;
2017-12-19 12:25:13 +01:00
render_ - > BindVertexBuffer ( softwareInputLayout_ , vertexBuffer , vertexBufferOffset ) ;
2017-11-19 12:25:57 +01:00
render_ - > Draw ( glprim [ prim ] , 0 , numTrans ) ;
2014-09-13 13:03:37 +02:00
}
} else if ( result . action = = SW_CLEAR ) {
u32 clearColor = result . color ;
float clearDepth = result . depth ;
bool colorMask = gstate . isClearModeColorMask ( ) ;
bool alphaMask = gstate . isClearModeAlphaMask ( ) ;
bool depthMask = gstate . isClearModeDepthMask ( ) ;
if ( depthMask ) {
framebufferManager_ - > SetDepthUpdated ( ) ;
}
GLbitfield target = 0 ;
2018-01-18 22:17:29 -08:00
// Without this, we will clear RGB when clearing stencil, which breaks games.
uint8_t rgbaMask = ( colorMask ? 7 : 0 ) | ( alphaMask ? 8 : 0 ) ;
2014-09-13 13:03:37 +02:00
if ( colorMask | | alphaMask ) target | = GL_COLOR_BUFFER_BIT ;
if ( alphaMask ) target | = GL_STENCIL_BUFFER_BIT ;
if ( depthMask ) target | = GL_DEPTH_BUFFER_BIT ;
2016-09-18 19:40:44 -07:00
int scissorX1 = gstate . getScissorX1 ( ) ;
int scissorY1 = gstate . getScissorY1 ( ) ;
2016-05-19 20:55:34 -07:00
int scissorX2 = gstate . getScissorX2 ( ) + 1 ;
int scissorY2 = gstate . getScissorY2 ( ) + 1 ;
2018-01-31 17:07:20 +01:00
2018-01-31 19:36:32 +01:00
render_ - > Clear ( clearColor , clearDepth , clearColor > > 24 , target , rgbaMask , vpAndScissor . scissorX , vpAndScissor . scissorY , vpAndScissor . scissorW , vpAndScissor . scissorH ) ;
2018-01-31 17:07:20 +01:00
framebufferManager_ - > SetColorUpdated ( gstate_c . skipDrawReason ) ;
2016-05-19 20:55:34 -07:00
framebufferManager_ - > SetSafeSize ( scissorX2 , scissorY2 ) ;
2016-09-18 19:40:44 -07:00
2017-01-28 10:04:50 +01:00
if ( g_Config . bBlockTransferGPU & & ( gstate_c . featureFlags & GPU_USE_CLEAR_RAM_HACK ) & & colorMask & & ( alphaMask | | gstate . FrameBufFormat ( ) = = GE_FORMAT_565 ) ) {
2017-04-09 15:10:07 -07:00
framebufferManager_ - > ApplyClearToMemory ( scissorX1 , scissorY1 , scissorX2 , scissorY2 , clearColor ) ;
2016-09-18 19:40:44 -07:00
}
2017-11-19 12:25:57 +01:00
gstate_c . Dirty ( DIRTY_BLEND_STATE ) ; // Make sure the color mask gets re-applied.
2014-09-13 13:03:37 +02:00
}
2012-12-20 14:10:42 +01:00
}
2012-12-19 18:35:37 +01:00
2014-10-19 20:25:04 +02:00
gpuStats . numDrawCalls + = numDrawCalls ;
2017-06-02 12:03:46 +02:00
gpuStats . numVertsSubmitted + = vertexCountInDrawCalls_ ;
2014-10-19 20:25:04 +02:00
2012-12-21 19:16:17 +01:00
indexGen . Reset ( ) ;
2014-03-23 15:34:04 +01:00
decodedVerts_ = 0 ;
2013-01-19 17:05:08 +01:00
numDrawCalls = 0 ;
2017-06-02 12:03:46 +02:00
vertexCountInDrawCalls_ = 0 ;
2013-11-10 15:22:24 +01:00
decodeCounter_ = 0 ;
2014-03-23 01:51:51 +01:00
dcid_ = 0 ;
2013-08-25 19:51:06 +02:00
prevPrim_ = GE_PRIM_INVALID ;
2014-03-24 11:19:11 +01:00
gstate_c . vertexFullAlpha = true ;
2015-07-26 22:38:40 +02:00
framebufferManager_ - > SetColorUpdated ( gstate_c . skipDrawReason ) ;
2013-09-22 00:18:46 -07:00
2015-03-15 21:38:01 -07:00
// Now seems as good a time as any to reset the min/max coords, which we may examine later.
2015-09-13 14:52:10 -07:00
gstate_c . vertBounds . minU = 512 ;
gstate_c . vertBounds . minV = 512 ;
gstate_c . vertBounds . maxU = 0 ;
gstate_c . vertBounds . maxV = 0 ;
2015-03-15 21:38:01 -07:00
2018-09-01 08:32:03 -07:00
GPUDebug : : NotifyDraw ( ) ;
2012-12-21 21:49:09 +01:00
}
2013-09-24 13:58:14 +02:00
2016-04-10 10:21:48 +02:00
bool DrawEngineGLES : : IsCodePtrVertexDecoder ( const u8 * ptr ) const {
2014-03-29 16:51:38 -07:00
return decJitCache_ - > IsInSpace ( ptr ) ;
}
2017-01-10 14:41:01 +09:00
2018-09-29 13:39:02 +09:00
void TessellationDataTransferGLES : : SendDataToShader ( const SimpleVertex * const * points , int size_u , int size_v , u32 vertType , const Spline : : Weight2D & weights ) {
2018-06-28 01:41:16 +09:00
bool hasColor = ( vertType & GE_VTYPE_COL_MASK ) ! = 0 ;
bool hasTexCoord = ( vertType & GE_VTYPE_TC_MASK ) ! = 0 ;
2018-09-22 22:06:40 +09:00
int size = size_u * size_v ;
2018-06-28 01:41:16 +09:00
float * pos = new float [ size * 4 ] ;
2018-06-30 00:21:30 +09:00
float * tex = hasTexCoord ? new float [ size * 4 ] : nullptr ;
2018-07-18 00:52:20 +09:00
float * col = hasColor ? new float [ size * 4 ] : nullptr ;
2018-06-28 01:41:16 +09:00
int stride = 4 ;
CopyControlPoints ( pos , tex , col , stride , stride , stride , points , size , vertType ) ;
2018-01-20 00:05:59 +01:00
// Removed the 1D texture support, it's unlikely to be relevant for performance.
2018-06-30 00:21:30 +09:00
// Control Points
2018-09-22 22:06:40 +09:00
if ( prevSizeU < size_u | | prevSizeV < size_v ) {
prevSizeU = size_u ;
prevSizeV = size_v ;
2018-07-21 00:18:34 +09:00
if ( ! data_tex [ 0 ] )
data_tex [ 0 ] = renderManager_ - > CreateTexture ( GL_TEXTURE_2D ) ;
2018-09-22 22:06:40 +09:00
renderManager_ - > TextureImage ( data_tex [ 0 ] , 0 , size_u * 3 , size_v , GL_RGBA32F , GL_RGBA , GL_FLOAT , nullptr , GLRAllocType : : NONE , false ) ;
2018-07-21 00:18:34 +09:00
renderManager_ - > FinalizeTexture ( data_tex [ 0 ] , 0 , false ) ;
}
2018-06-30 00:21:30 +09:00
renderManager_ - > BindTexture ( TEX_SLOT_SPLINE_POINTS , data_tex [ 0 ] ) ;
// Position
2018-09-22 22:06:40 +09:00
renderManager_ - > TextureSubImage ( data_tex [ 0 ] , 0 , 0 , 0 , size_u , size_v , GL_RGBA , GL_FLOAT , ( u8 * ) pos , GLRAllocType : : NEW ) ;
2018-06-28 01:41:16 +09:00
// Texcoord
2018-06-30 00:21:30 +09:00
if ( hasTexCoord )
2018-09-22 22:06:40 +09:00
renderManager_ - > TextureSubImage ( data_tex [ 0 ] , 0 , size_u , 0 , size_u , size_v , GL_RGBA , GL_FLOAT , ( u8 * ) tex , GLRAllocType : : NEW ) ;
2018-06-28 01:41:16 +09:00
// Color
2018-07-18 00:52:20 +09:00
if ( hasColor )
2018-09-22 22:06:40 +09:00
renderManager_ - > TextureSubImage ( data_tex [ 0 ] , 0 , size_u * 2 , 0 , size_u , size_v , GL_RGBA , GL_FLOAT , ( u8 * ) col , GLRAllocType : : NEW ) ;
2018-07-11 01:09:20 +09:00
// Weight U
2018-07-21 00:18:34 +09:00
if ( prevSizeWU < weights . size_u ) {
prevSizeWU = weights . size_u ;
if ( ! data_tex [ 1 ] )
data_tex [ 1 ] = renderManager_ - > CreateTexture ( GL_TEXTURE_2D ) ;
renderManager_ - > TextureImage ( data_tex [ 1 ] , 0 , weights . size_u * 2 , 1 , GL_RGBA32F , GL_RGBA , GL_FLOAT , nullptr , GLRAllocType : : NONE , false ) ;
renderManager_ - > FinalizeTexture ( data_tex [ 1 ] , 0 , false ) ;
}
2018-07-11 01:09:20 +09:00
renderManager_ - > BindTexture ( TEX_SLOT_SPLINE_WEIGHTS_U , data_tex [ 1 ] ) ;
2018-07-21 00:18:34 +09:00
renderManager_ - > TextureSubImage ( data_tex [ 1 ] , 0 , 0 , 0 , weights . size_u * 2 , 1 , GL_RGBA , GL_FLOAT , ( u8 * ) weights . u , GLRAllocType : : NONE ) ;
2018-07-11 01:09:20 +09:00
// Weight V
2018-07-21 00:18:34 +09:00
if ( prevSizeWV < weights . size_v ) {
prevSizeWV = weights . size_v ;
if ( ! data_tex [ 2 ] )
data_tex [ 2 ] = renderManager_ - > CreateTexture ( GL_TEXTURE_2D ) ;
renderManager_ - > TextureImage ( data_tex [ 2 ] , 0 , weights . size_v * 2 , 1 , GL_RGBA32F , GL_RGBA , GL_FLOAT , nullptr , GLRAllocType : : NONE , false ) ;
renderManager_ - > FinalizeTexture ( data_tex [ 2 ] , 0 , false ) ;
}
2018-07-11 01:09:20 +09:00
renderManager_ - > BindTexture ( TEX_SLOT_SPLINE_WEIGHTS_V , data_tex [ 2 ] ) ;
2018-07-21 00:18:34 +09:00
renderManager_ - > TextureSubImage ( data_tex [ 2 ] , 0 , 0 , 0 , weights . size_v * 2 , 1 , GL_RGBA , GL_FLOAT , ( u8 * ) weights . v , GLRAllocType : : NONE ) ;
2018-01-20 00:05:59 +01:00
}
2017-01-26 22:17:31 +09:00
2018-07-13 18:35:44 +09:00
void TessellationDataTransferGLES : : EndFrame ( ) {
2018-01-20 00:05:59 +01:00
for ( int i = 0 ; i < 3 ; i + + ) {
if ( data_tex [ i ] ) {
renderManager_ - > DeleteTexture ( data_tex [ i ] ) ;
data_tex [ i ] = nullptr ;
2017-01-26 22:17:31 +09:00
}
2017-01-09 03:37:21 +09:00
}
2018-09-22 22:06:40 +09:00
prevSizeU = prevSizeV = prevSizeWU = prevSizeWV = 0 ;
2017-01-09 03:37:21 +09:00
}