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 11:01:52 +02:00
// Ideas for speeding things up on mobile OpenGL ES implementations
//
// Use superbuffers! Yes I just invented that name.
//
// The idea is to avoid respecifying the vertex format between every draw call (multiple glVertexAttribPointer ...)
// by combining the contents of multiple draw calls into one buffer, as long as
// they have exactly the same output vertex format. (different input formats is fine! This way
// we can combine the data for multiple draws with different numbers of bones, as we consider numbones < 4 to be = 4)
// into one VBO.
//
// This will likely be a win because I believe that between every change of VBO + glVertexAttribPointer*N, the driver will
// perform a lot of validation, probably at draw call time, while all the validation can be skipped if the only thing
// that changes between two draw calls is simple state or texture or a matrix etc, not anything vertex related.
// Also the driver will have to manage hundreds instead of thousands of VBOs in games like GTA.
//
// * Every 10 frames or something, do the following:
// - Frame 1:
// + Mark all drawn buffers with in-frame sequence numbers (alternatively,
// just log them in an array)
// - Frame 2 (beginning?):
// + Take adjacent buffers that have the same output vertex format, and add them
// to a list of buffers to combine. Create said buffers with appropriate sizes
// and precompute the offsets that the draws should be written into.
// - Frame 2 (end):
// + Actually do the work of combining the buffers. This probably means re-decoding
// the vertices into a new one. Will also have to apply index offsets.
//
// Also need to change the drawing code so that we don't glBindBuffer and respecify glVAP if
// two subsequent drawcalls come from the same superbuffer.
//
// Or we ignore all of this including vertex caching and simply find a way to do highly optimized vertex streaming,
// like Dolphin is trying to. That will likely never be able to reach the same speed as perfectly optimized
// superbuffers though. For this we will have to JIT the vertex decoder but that's not too hard.
//
// Now, when do we delete superbuffers? Maybe when half the buffers within have been killed?
//
// Another idea for GTA which switches textures a lot while not changing much other state is to use ES 3 Array
// textures, if they are the same size (even if they aren't, might be okay to simply resize the textures to match
// if they're just a multiple of 2 away) or something. Then we'd have to add a W texture coordinate to choose the
// texture within the bound texture array to the vertex data when merging into superbuffers.
//
// There are even more things to try. For games that do matrix palette skinning by quickly switching bones and
// just drawing a few triangles per call (NBA, FF:CC, Tekken 6 etc) we could even collect matrices, upload them
// all at once, writing matrix indices into the vertices in addition to the weights, and then doing a single
// draw call with specially generated shader to draw the whole mesh. This code will be seriously complex though.
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/Host.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"
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 ) ;
splineBuffer = ( u8 * ) AllocateMemoryPages ( SPLINE_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
2017-01-27 12:49:27 +09:00
tessDataTransfer = new TessellationDataTransferGLES ( gl_extensions . VersionGEThan ( 3 , 0 , 0 ) ) ;
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 ) ;
2015-01-29 14:12:24 +01:00
FreeMemoryPages ( splineBuffer , SPLINE_BUFFER_SIZE ) ;
2013-09-24 11:14:04 +02:00
2017-01-09 03:37:21 +09:00
delete tessDataTransfer ;
2013-01-10 12:51:18 +01:00
}
2017-12-09 23:58:08 +01:00
void DrawEngineGLES : : DeviceLost ( ) {
DestroyDeviceObjects ( ) ;
}
void DrawEngineGLES : : DeviceRestore ( ) {
InitDeviceObjects ( ) ;
}
2016-04-10 10:21:48 +02:00
void DrawEngineGLES : : InitDeviceObjects ( ) {
2017-11-19 12:25:57 +01:00
for ( int i = 0 ; i < GLRenderManager : : MAX_INFLIGHT_FRAMES ; i + + ) {
2017-11-19 18:22:46 +01:00
frameData_ [ i ] . pushVertex = new GLPushBuffer ( render_ , GL_ARRAY_BUFFER , 1024 * 1024 ) ;
2017-12-21 19:05:33 +01:00
frameData_ [ i ] . pushIndex = new GLPushBuffer ( render_ , 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 ( ) {
2017-11-19 12:25:57 +01:00
for ( int i = 0 ; i < GLRenderManager : : MAX_INFLIGHT_FRAMES ; i + + ) {
frameData_ [ i ] . pushVertex - > Destroy ( ) ;
frameData_ [ i ] . pushIndex - > Destroy ( ) ;
delete frameData_ [ i ] . pushVertex ;
delete frameData_ [ i ] . pushIndex ;
}
2015-12-23 18:17:22 -08:00
ClearTrackedVertexArrays ( ) ;
2017-11-19 12:25:57 +01:00
render_ - > DeleteInputLayout ( softwareInputLayout_ ) ;
}
void DrawEngineGLES : : ClearInputLayoutMap ( ) {
inputLayoutMap_ . Iterate ( [ & ] ( const uint32_t & key , GLRInputLayout * il ) {
render_ - > DeleteInputLayout ( il ) ;
} ) ;
inputLayoutMap_ . Clear ( ) ;
}
void DrawEngineGLES : : BeginFrame ( ) {
FrameData & frameData = frameData_ [ render_ - > GetCurFrame ( ) ] ;
frameData . pushIndex - > Begin ( ) ;
frameData . pushVertex - > Begin ( ) ;
}
void DrawEngineGLES : : EndFrame ( ) {
FrameData & frameData = frameData_ [ render_ - > GetCurFrame ( ) ] ;
frameData . pushIndex - > End ( ) ;
frameData . pushVertex - > End ( ) ;
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 ;
VertexAttribSetup ( ATTR_W1 , decFmt . w0fmt , decFmt . stride , decFmt . w0off , entries ) ;
VertexAttribSetup ( ATTR_W2 , decFmt . w1fmt , decFmt . stride , decFmt . w1off , entries ) ;
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
}
2016-04-10 10:21:48 +02:00
void DrawEngineGLES : : SubmitPrim ( void * verts , void * inds , GEPrimitiveType prim , int vertexCount , u32 vertType , int * bytesRead ) {
2017-06-02 12:03:46 +02:00
if ( ! indexGen . PrimCompatible ( prevPrim_ , prim ) | | numDrawCalls > = MAX_DEFERRED_DRAW_CALLS | | vertexCountInDrawCalls_ + vertexCount > VERTEX_BUFFER_MAX )
2012-12-21 19:16:17 +01:00
Flush ( ) ;
2013-10-09 11:01:52 +02:00
2013-09-07 22:31:22 -07:00
// TODO: Is this the right thing to do?
2013-09-04 17:12:53 +08:00
if ( prim = = GE_PRIM_KEEP_PREVIOUS ) {
2014-10-29 23:50:21 +01:00
prim = prevPrim_ ! = GE_PRIM_INVALID ? prevPrim_ : GE_PRIM_POINTS ;
2014-10-19 20:25:04 +02:00
} else {
prevPrim_ = prim ;
2013-09-04 17:12:53 +08:00
}
2013-10-09 11:01:52 +02:00
2017-06-02 13:06:14 +02:00
SetupVertexDecoder ( vertType ) ;
2012-12-28 19:33:26 +01:00
2014-10-19 20:25:04 +02:00
* bytesRead = vertexCount * dec_ - > VertexSize ( ) ;
2013-01-19 17:05:08 +01:00
2015-02-28 01:28:30 -08:00
if ( ( vertexCount < 2 & & prim > 0 ) | | ( vertexCount < 3 & & prim > 2 & & prim ! = GE_PRIM_RECTANGLES ) )
return ;
2013-07-28 00:18:41 +02:00
DeferredDrawCall & dc = drawCalls [ numDrawCalls ] ;
2013-01-19 17:05:08 +01:00
dc . verts = verts ;
dc . inds = inds ;
dc . vertType = vertType ;
2013-11-14 14:03:03 +01:00
dc . indexType = ( vertType & GE_VTYPE_IDX_MASK ) > > GE_VTYPE_IDX_SHIFT ;
2013-01-19 17:05:08 +01:00
dc . prim = prim ;
dc . vertexCount = vertexCount ;
2014-03-23 01:51:51 +01:00
u32 dhash = dcid_ ;
2014-03-23 15:34:04 +01:00
dhash ^ = ( u32 ) ( uintptr_t ) verts ;
2014-03-23 01:51:51 +01:00
dhash = __rotl ( dhash , 13 ) ;
2014-03-23 15:34:04 +01:00
dhash ^ = ( u32 ) ( uintptr_t ) inds ;
2014-03-23 01:51:51 +01:00
dhash = __rotl ( dhash , 13 ) ;
2014-03-23 15:34:04 +01:00
dhash ^ = ( u32 ) vertType ;
2014-03-23 01:51:51 +01:00
dhash = __rotl ( dhash , 13 ) ;
2014-03-23 15:34:04 +01:00
dhash ^ = ( u32 ) vertexCount ;
2014-03-23 01:51:51 +01:00
dhash = __rotl ( dhash , 13 ) ;
2014-03-23 15:34:04 +01:00
dhash ^ = ( u32 ) prim ;
2014-03-23 01:51:51 +01:00
dcid_ = dhash ;
2013-01-19 17:05:08 +01:00
if ( inds ) {
GetIndexBounds ( inds , vertexCount , vertType , & dc . indexLowerBound , & dc . indexUpperBound ) ;
} else {
dc . indexLowerBound = 0 ;
dc . indexUpperBound = vertexCount - 1 ;
}
2013-07-28 00:18:41 +02:00
2016-12-20 13:27:44 +01:00
uvScale [ numDrawCalls ] = gstate_c . uv ;
2013-11-10 15:31:56 +01:00
2013-07-28 00:18:41 +02:00
numDrawCalls + + ;
2017-06-02 12:03:46 +02:00
vertexCountInDrawCalls_ + = vertexCount ;
2013-11-10 15:31:56 +01:00
if ( g_Config . bSoftwareSkinning & & ( vertType & GE_VTYPE_WEIGHT_MASK ) ) {
2017-06-02 12:09:57 +02:00
DecodeVertsStep ( decoded , decodeCounter_ , decodedVerts_ ) ;
2013-11-10 15:31:56 +01:00
decodeCounter_ + + ;
}
2014-06-22 20:37:50 +02:00
if ( prim = = GE_PRIM_RECTANGLES & & ( gstate . getTextureAddress ( 0 ) & 0x3FFFFFFF ) = = ( gstate . getFrameBufAddress ( ) & 0x3FFFFFFF ) ) {
2014-10-19 20:25:04 +02:00
// Rendertarget == texture?
2014-07-08 23:32:41 -07:00
if ( ! g_Config . bDisableSlowFramebufEffects ) {
2017-01-24 09:41:38 +01:00
gstate_c . Dirty ( DIRTY_TEXTURE_PARAMS ) ;
2014-07-08 23:32:41 -07:00
Flush ( ) ;
}
2014-06-22 20:37:50 +02:00
}
2013-01-19 17:05:08 +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 ;
}
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 ) ;
// Also avoid caching when software skinning.
if ( g_Config . bSoftwareSkinning & & ( lastVType_ & GE_VTYPE_WEIGHT_MASK ) )
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 {
2017-12-14 16:36:05 +01:00
if ( g_Config . bSoftwareSkinning & & ( lastVType_ & GE_VTYPE_WEIGHT_MASK ) ) {
// If software skinning, we've already predecoded into "decoded". So push that content.
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 ) ;
}
2017-01-09 03:37:21 +09:00
if ( gstate_c . bezier | | gstate_c . spline )
2017-12-19 12:25:13 +01:00
render_ - > DrawIndexed ( glprim [ prim ] , vertexCount , GL_UNSIGNED_SHORT , ( GLvoid * ) ( intptr_t ) indexBufferOffset , numPatches ) ;
2017-01-09 03:37:21 +09:00
else
2017-11-19 12:25:57 +01: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 ;
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 ;
const float col [ 4 ] = {
( ( clearColor & 0xFF ) ) / 255.0f ,
( ( clearColor & 0xFF00 ) > > 8 ) / 255.0f ,
( ( clearColor & 0xFF0000 ) > > 16 ) / 255.0f ,
( ( clearColor & 0xFF000000 ) > > 24 ) / 255.0f ,
} ;
bool colorMask = gstate . isClearModeColorMask ( ) ;
bool alphaMask = gstate . isClearModeAlphaMask ( ) ;
bool depthMask = gstate . isClearModeDepthMask ( ) ;
if ( depthMask ) {
framebufferManager_ - > SetDepthUpdated ( ) ;
}
GLbitfield target = 0 ;
if ( colorMask | | alphaMask ) target | = GL_COLOR_BUFFER_BIT ;
if ( alphaMask ) target | = GL_STENCIL_BUFFER_BIT ;
if ( depthMask ) target | = GL_DEPTH_BUFFER_BIT ;
2017-11-19 12:25:57 +01:00
render_ - > Clear ( clearColor , clearDepth , clearColor > > 24 , target ) ;
2015-07-26 22:38:40 +02:00
framebufferManager_ - > SetColorUpdated ( gstate_c . skipDrawReason ) ;
2016-05-19 20:55:34 -07:00
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 ;
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
2014-02-08 10:29:22 -08:00
# ifndef MOBILE_DEVICE
2013-09-22 00:18:46 -07:00
host - > GPUNotifyDraw ( ) ;
# endif
2017-03-03 14:15:27 +01:00
CHECK_GL_ERROR_IF_DEBUG ( ) ;
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
2017-01-09 03:37:21 +09:00
void DrawEngineGLES : : TessellationDataTransferGLES : : SendDataToShader ( const float * pos , const float * tex , const float * col , int size , bool hasColor , bool hasTexCoords ) {
2017-12-12 14:07:52 +01:00
/*
2017-01-27 12:49:27 +09:00
# ifndef USING_GLES2
2017-03-03 12:32:01 +01:00
if ( isAllowTexture1D_ ) {
2017-01-26 22:17:31 +09:00
// Position
2017-02-25 17:22:54 +09:00
glActiveTexture ( GL_TEXTURE4 ) ;
2017-01-26 22:17:31 +09:00
glBindTexture ( GL_TEXTURE_1D , data_tex [ 0 ] ) ;
2017-01-10 14:16:03 +09:00
glTexParameteri ( GL_TEXTURE_1D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_1D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_1D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_1D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
2017-01-26 22:17:31 +09:00
if ( prevSize < size ) {
2017-03-24 13:29:05 +09:00
glTexImage1D ( GL_TEXTURE_1D , 0 , GL_RGBA32F , size , 0 , GL_RGBA , GL_FLOAT , ( GLfloat * ) pos ) ;
2017-01-26 22:17:31 +09:00
prevSize = size ;
2017-01-09 03:37:21 +09:00
} else {
2017-03-24 13:29:05 +09:00
glTexSubImage1D ( GL_TEXTURE_1D , 0 , 0 , size , GL_RGBA , GL_FLOAT , ( GLfloat * ) pos ) ;
2017-01-09 03:37:21 +09:00
}
2017-01-26 22:17:31 +09:00
// Texcoords
if ( hasTexCoords ) {
2017-02-25 17:22:54 +09:00
glActiveTexture ( GL_TEXTURE5 ) ;
2017-01-26 22:17:31 +09:00
glBindTexture ( GL_TEXTURE_1D , data_tex [ 1 ] ) ;
glTexParameteri ( GL_TEXTURE_1D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_1D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_1D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_1D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
if ( prevSizeTex < size ) {
2017-03-24 13:29:05 +09:00
glTexImage1D ( GL_TEXTURE_1D , 0 , GL_RGBA32F , size , 0 , GL_RGBA , GL_FLOAT , ( GLfloat * ) tex ) ;
2017-01-26 22:17:31 +09:00
prevSizeTex = size ;
} else {
2017-03-24 13:29:05 +09:00
glTexSubImage1D ( GL_TEXTURE_1D , 0 , 0 , size , GL_RGBA , GL_FLOAT , ( GLfloat * ) tex ) ;
2017-01-26 22:17:31 +09:00
}
}
// Color
2017-02-25 17:22:54 +09:00
glActiveTexture ( GL_TEXTURE6 ) ;
2017-01-26 22:17:31 +09:00
glBindTexture ( GL_TEXTURE_1D , data_tex [ 2 ] ) ;
glTexParameteri ( GL_TEXTURE_1D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_1D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_1D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_1D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
int sizeColor = hasColor ? size : 1 ;
if ( prevSizeCol < sizeColor ) {
glTexImage1D ( GL_TEXTURE_1D , 0 , GL_RGBA32F , sizeColor , 0 , GL_RGBA , GL_FLOAT , ( GLfloat * ) col ) ;
prevSizeCol = sizeColor ;
} else {
glTexSubImage1D ( GL_TEXTURE_1D , 0 , 0 , sizeColor , GL_RGBA , GL_FLOAT , ( GLfloat * ) col ) ;
}
2017-01-27 12:49:27 +09:00
} else
# endif
{
2017-01-26 22:17:31 +09:00
// Position
2017-02-25 17:22:54 +09:00
glActiveTexture ( GL_TEXTURE4 ) ;
2017-01-26 22:17:31 +09:00
glBindTexture ( GL_TEXTURE_2D , data_tex [ 0 ] ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
if ( prevSize < size ) {
2017-03-24 13:29:05 +09:00
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA32F , size , 1 , 0 , GL_RGBA , GL_FLOAT , ( GLfloat * ) pos ) ;
2017-01-26 22:17:31 +09:00
prevSize = size ;
} else {
2017-03-24 13:29:05 +09:00
glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , size , 1 , GL_RGBA , GL_FLOAT , ( GLfloat * ) pos ) ;
2017-01-26 22:17:31 +09:00
}
// Texcoords
if ( hasTexCoords ) {
2017-02-25 17:22:54 +09:00
glActiveTexture ( GL_TEXTURE5 ) ;
2017-01-26 22:17:31 +09:00
glBindTexture ( GL_TEXTURE_2D , data_tex [ 1 ] ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
if ( prevSizeTex < size ) {
2017-03-24 13:29:05 +09:00
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA32F , size , 1 , 0 , GL_RGBA , GL_FLOAT , ( GLfloat * ) tex ) ;
2017-01-26 22:17:31 +09:00
prevSizeTex = size ;
} else {
2017-03-24 13:29:05 +09:00
glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , size , 1 , GL_RGBA , GL_FLOAT , ( GLfloat * ) tex ) ;
2017-01-26 22:17:31 +09:00
}
}
// Color
2017-02-25 17:22:54 +09:00
glActiveTexture ( GL_TEXTURE6 ) ;
2017-01-26 22:17:31 +09:00
glBindTexture ( GL_TEXTURE_2D , data_tex [ 2 ] ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
int sizeColor = hasColor ? size : 1 ;
if ( prevSizeCol < sizeColor ) {
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA32F , sizeColor , 1 , 0 , GL_RGBA , GL_FLOAT , ( GLfloat * ) col ) ;
prevSizeCol = sizeColor ;
} else {
glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , sizeColor , 1 , GL_RGBA , GL_FLOAT , ( GLfloat * ) col ) ;
}
2017-01-09 03:37:21 +09:00
}
glActiveTexture ( GL_TEXTURE0 ) ;
2017-03-03 14:15:27 +01:00
CHECK_GL_ERROR_IF_DEBUG ( ) ;
2017-12-12 14:07:52 +01:00
*/
2017-01-09 03:37:21 +09:00
}