2013-08-17 11:23:51 +02: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
// the Free Software Foundation, version 2.0 or later versions.
// 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/.
2020-09-15 00:34:45 +02:00
# include <algorithm>
2020-08-15 12:25:39 +02:00
# include "Common/Log.h"
2013-08-17 11:23:51 +02:00
# include "Common/MemoryUtil.h"
2020-08-15 20:53:08 +02:00
# include "Common/TimeUtil.h"
2013-08-17 11:23:51 +02:00
# include "Core/MemMap.h"
# include "Core/System.h"
# include "Core/Config.h"
# include "Core/CoreTiming.h"
2020-10-04 23:24:14 +02:00
# include "Common/GPU/D3D9/D3D9StateCache.h"
2013-08-17 11:23:51 +02:00
# include "GPU/Math3D.h"
# include "GPU/GPUState.h"
# include "GPU/ge_constants.h"
2014-08-24 22:16:32 -07:00
# include "GPU/Common/SplineCommon.h"
2014-04-18 14:30:18 +02:00
# include "GPU/Common/TransformCommon.h"
2014-09-10 10:44:22 +02:00
# include "GPU/Common/VertexDecoderCommon.h"
2014-09-13 13:53:04 +02:00
# include "GPU/Common/SoftwareTransformCommon.h"
2018-09-01 08:32:03 -07:00
# include "GPU/Debugger/Debugger.h"
2013-09-15 12:46:14 +02:00
# include "GPU/Directx9/TextureCacheDX9.h"
2016-04-10 10:27:28 +02:00
# include "GPU/Directx9/DrawEngineDX9.h"
2013-09-15 12:46:14 +02:00
# include "GPU/Directx9/ShaderManagerDX9.h"
# include "GPU/Directx9/GPU_DX9.h"
2013-08-17 11:23:51 +02:00
2020-01-26 15:28:54 +01:00
static const D3DPRIMITIVETYPE d3d_prim [ 8 ] = {
2021-10-31 13:06:06 -07:00
// Points, which are expanded to triangles.
D3DPT_TRIANGLELIST ,
2021-10-31 14:46:46 -07:00
// Lines and line strips, which are also expanded to triangles.
D3DPT_TRIANGLELIST ,
D3DPT_TRIANGLELIST ,
2013-08-17 11:23:51 +02:00
D3DPT_TRIANGLELIST ,
D3DPT_TRIANGLESTRIP ,
D3DPT_TRIANGLEFAN ,
2021-10-31 13:06:06 -07:00
// Rectangles, which are expanded to triangles.
2020-01-26 15:28:54 +01:00
D3DPT_TRIANGLELIST ,
2013-08-17 11:23:51 +02:00
} ;
2013-09-15 12:46:14 +02:00
static const int D3DPRIMITIVEVERTEXCOUNT [ 8 ] [ 2 ] = {
{ 0 , 0 } , // invalid
{ 1 , 0 } , // 1 = D3DPT_POINTLIST,
{ 2 , 0 } , // 2 = D3DPT_LINELIST,
{ 2 , 1 } , // 3 = D3DPT_LINESTRIP,
{ 3 , 0 } , // 4 = D3DPT_TRIANGLELIST,
{ 1 , 2 } , // 5 = D3DPT_TRIANGLESTRIP,
{ 1 , 2 } , // 6 = D3DPT_TRIANGLEFAN,
} ;
2017-02-05 20:36:00 +01:00
inline int D3DPrimCount ( D3DPRIMITIVETYPE prim , int size ) {
2013-08-17 11:23:51 +02:00
return ( size / D3DPRIMITIVEVERTEXCOUNT [ prim ] [ 0 ] ) - D3DPRIMITIVEVERTEXCOUNT [ prim ] [ 1 ] ;
}
enum {
2013-10-27 14:43:58 -07:00
TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof ( TransformedVertex )
2013-08-17 11:23:51 +02:00
} ;
2013-08-20 18:47:11 +02:00
# define VERTEXCACHE_DECIMATION_INTERVAL 17
2014-09-14 13:50:57 -07:00
enum { VAI_KILL_AGE = 120 , VAI_UNRELIABLE_KILL_AGE = 240 , VAI_UNRELIABLE_KILL_MAX = 4 } ;
2017-02-05 19:38:52 +01:00
static const D3DVERTEXELEMENT9 TransformedVertexElements [ ] = {
2021-10-24 12:07:57 -07:00
{ 0 , offsetof ( TransformedVertex , pos ) , D3DDECLTYPE_FLOAT4 , D3DDECLMETHOD_DEFAULT , D3DDECLUSAGE_POSITION , 0 } ,
{ 0 , offsetof ( TransformedVertex , uv ) , D3DDECLTYPE_FLOAT3 , D3DDECLMETHOD_DEFAULT , D3DDECLUSAGE_TEXCOORD , 0 } ,
{ 0 , offsetof ( TransformedVertex , color0 ) , D3DDECLTYPE_UBYTE4N , D3DDECLMETHOD_DEFAULT , D3DDECLUSAGE_COLOR , 0 } ,
{ 0 , offsetof ( TransformedVertex , color1 ) , D3DDECLTYPE_UBYTE4N , D3DDECLMETHOD_DEFAULT , D3DDECLUSAGE_COLOR , 1 } ,
{ 0 , offsetof ( TransformedVertex , fog ) , D3DDECLTYPE_FLOAT1 , D3DDECLMETHOD_DEFAULT , D3DDECLUSAGE_NORMAL , 0 } ,
2017-02-05 19:38:52 +01:00
D3DDECL_END ( )
} ;
2020-05-24 20:57:59 +02:00
DrawEngineDX9 : : DrawEngineDX9 ( Draw : : DrawContext * draw ) : draw_ ( draw ) , vai_ ( 256 ) , vertexDeclMap_ ( 64 ) {
2017-03-02 11:39:02 +01:00
device_ = ( LPDIRECT3DDEVICE9 ) draw - > GetNativeObject ( Draw : : NativeObject : : DEVICE ) ;
2014-09-12 01:38:45 +02:00
decOptions_ . expandAllWeightsToFloat = true ;
decOptions_ . expand8BitNormalsToFloat = true ;
2014-09-10 10:28:44 +02:00
2013-11-15 14:24:25 +01:00
decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL ;
2013-12-03 16:53:30 +01:00
indexGen . Setup ( decIndex ) ;
2014-09-12 01:48:43 +02:00
2013-12-03 16:53:30 +01:00
InitDeviceObjects ( ) ;
2017-01-10 14:41:01 +09:00
2018-07-13 18:35:44 +09:00
tessDataTransferDX9 = new TessellationDataTransferDX9 ( ) ;
tessDataTransfer = tessDataTransferDX9 ;
2017-02-05 19:38:52 +01:00
2017-02-05 20:36:00 +01:00
device_ - > CreateVertexDeclaration ( TransformedVertexElements , & transformedVertexDecl_ ) ;
2013-08-17 11:23:51 +02:00
}
2016-04-10 10:21:48 +02:00
DrawEngineDX9 : : ~ DrawEngineDX9 ( ) {
2017-02-05 19:38:52 +01:00
if ( transformedVertexDecl_ ) {
transformedVertexDecl_ - > Release ( ) ;
}
2013-08-17 11:23:51 +02:00
DestroyDeviceObjects ( ) ;
2017-08-20 11:30:19 +02:00
vertexDeclMap_ . Iterate ( [ & ] ( const uint32_t & key , IDirect3DVertexDeclaration9 * decl ) {
if ( decl ) {
decl - > Release ( ) ;
2014-09-09 00:29:01 +02:00
}
2017-08-20 11:30:19 +02:00
} ) ;
vertexDeclMap_ . Clear ( ) ;
2018-07-13 18:35:44 +09:00
delete tessDataTransferDX9 ;
2013-08-17 11:23:51 +02:00
}
2016-04-10 10:21:48 +02:00
void DrawEngineDX9 : : InitDeviceObjects ( ) {
2022-11-24 10:38:49 +01:00
draw_ - > SetInvalidationCallback ( std : : bind ( & DrawEngineDX9 : : Invalidate , this , std : : placeholders : : _1 ) ) ;
2013-08-17 11:23:51 +02:00
}
2016-04-10 10:21:48 +02:00
void DrawEngineDX9 : : DestroyDeviceObjects ( ) {
2023-03-14 17:52:40 +01:00
if ( draw_ ) {
draw_ - > SetInvalidationCallback ( InvalidationCallback ( ) ) ;
}
2013-08-17 11:23:51 +02:00
ClearTrackedVertexArrays ( ) ;
}
2013-08-23 17:24:51 +02:00
2013-08-21 11:10:56 +02:00
struct DeclTypeInfo {
u32 type ;
2013-09-01 08:38:40 +02:00
const char * name ;
2013-08-21 11:10:56 +02:00
} ;
2013-08-23 17:24:51 +02:00
2013-08-21 11:10:56 +02:00
static const DeclTypeInfo VComp [ ] = {
2014-09-17 22:03:44 +02:00
{ 0 , " NULL " } , // DEC_NONE,
{ D3DDECLTYPE_FLOAT1 , " D3DDECLTYPE_FLOAT1 " } , // DEC_FLOAT_1,
{ D3DDECLTYPE_FLOAT2 , " D3DDECLTYPE_FLOAT2 " } , // DEC_FLOAT_2,
{ D3DDECLTYPE_FLOAT3 , " D3DDECLTYPE_FLOAT3 " } , // DEC_FLOAT_3,
{ D3DDECLTYPE_FLOAT4 , " D3DDECLTYPE_FLOAT4 " } , // DEC_FLOAT_4,
2013-09-15 12:46:14 +02:00
2014-09-17 22:03:44 +02:00
{ 0 , " UNUSED " } , // DEC_S8_3,
{ D3DDECLTYPE_SHORT4N , " D3DDECLTYPE_SHORT4N " } , // DEC_S16_3,
{ D3DDECLTYPE_UBYTE4N , " D3DDECLTYPE_UBYTE4N " } , // DEC_U8_1,
{ D3DDECLTYPE_UBYTE4N , " D3DDECLTYPE_UBYTE4N " } , // DEC_U8_2,
{ D3DDECLTYPE_UBYTE4N , " D3DDECLTYPE_UBYTE4N " } , // DEC_U8_3,
{ D3DDECLTYPE_UBYTE4N , " D3DDECLTYPE_UBYTE4N " } , // DEC_U8_4,
{ 0 , " UNUSED_DEC_U16_1 " } , // DEC_U16_1,
{ 0 , " UNUSED_DEC_U16_2 " } , // DEC_U16_2,
{ D3DDECLTYPE_USHORT4N , " D3DDECLTYPE_USHORT4N " } , // DEC_U16_3,
{ D3DDECLTYPE_USHORT4N , " D3DDECLTYPE_USHORT4N " } , // DEC_U16_4,
2013-08-21 11:10:56 +02:00
} ;
static void VertexAttribSetup ( D3DVERTEXELEMENT9 * VertexElement , u8 fmt , u8 offset , u8 usage , u8 usage_index = 0 ) {
memset ( VertexElement , 0 , sizeof ( D3DVERTEXELEMENT9 ) ) ;
VertexElement - > Offset = offset ;
2014-08-26 07:37:19 -07:00
VertexElement - > Type = VComp [ fmt ] . type ;
2013-08-21 11:10:56 +02:00
VertexElement - > Usage = usage ;
VertexElement - > UsageIndex = usage_index ;
}
2016-04-10 10:21:48 +02:00
IDirect3DVertexDeclaration9 * DrawEngineDX9 : : SetupDecFmtForDraw ( VSShader * vshader , const DecVtxFormat & decFmt , u32 pspFmt ) {
2017-08-20 11:30:19 +02:00
IDirect3DVertexDeclaration9 * vertexDeclCached = vertexDeclMap_ . Get ( pspFmt ) ;
2013-09-01 08:38:40 +02:00
2017-08-20 11:30:19 +02:00
if ( vertexDeclCached ) {
return vertexDeclCached ;
} else {
2014-09-07 13:07:12 -07:00
D3DVERTEXELEMENT9 VertexElements [ 8 ] ;
D3DVERTEXELEMENT9 * VertexElement = & VertexElements [ 0 ] ;
2013-09-01 08:38:40 +02:00
// Vertices Elements orders
2018-04-10 11:21:56 +02:00
// WEIGHT
if ( decFmt . w0fmt ! = 0 ) {
VertexAttribSetup ( VertexElement , decFmt . w0fmt , decFmt . w0off , D3DDECLUSAGE_TEXCOORD , 1 ) ;
VertexElement + + ;
}
if ( decFmt . w1fmt ! = 0 ) {
VertexAttribSetup ( VertexElement , decFmt . w1fmt , decFmt . w1off , D3DDECLUSAGE_TEXCOORD , 2 ) ;
VertexElement + + ;
}
2013-09-01 08:38:40 +02:00
// TC
if ( decFmt . uvfmt ! = 0 ) {
2014-09-09 00:42:12 +02:00
VertexAttribSetup ( VertexElement , decFmt . uvfmt , decFmt . uvoff , D3DDECLUSAGE_TEXCOORD , 0 ) ;
2013-09-01 08:38:40 +02:00
VertexElement + + ;
}
// COLOR
if ( decFmt . c0fmt ! = 0 ) {
2014-08-25 01:16:49 -07:00
VertexAttribSetup ( VertexElement , decFmt . c0fmt , decFmt . c0off , D3DDECLUSAGE_COLOR , 0 ) ;
2013-09-01 08:38:40 +02:00
VertexElement + + ;
}
// Never used ?
if ( decFmt . c1fmt ! = 0 ) {
2014-08-25 01:16:49 -07:00
VertexAttribSetup ( VertexElement , decFmt . c1fmt , decFmt . c1off , D3DDECLUSAGE_COLOR , 1 ) ;
2013-09-01 08:38:40 +02:00
VertexElement + + ;
}
// NORMAL
if ( decFmt . nrmfmt ! = 0 ) {
VertexAttribSetup ( VertexElement , decFmt . nrmfmt , decFmt . nrmoff , D3DDECLUSAGE_NORMAL , 0 ) ;
VertexElement + + ;
}
// POSITION
// Always
VertexAttribSetup ( VertexElement , decFmt . posfmt , decFmt . posoff , D3DDECLUSAGE_POSITION , 0 ) ;
VertexElement + + ;
// End
D3DVERTEXELEMENT9 end = D3DDECL_END ( ) ;
memcpy ( VertexElement , & end , sizeof ( D3DVERTEXELEMENT9 ) ) ;
2014-09-18 00:40:25 +02:00
2014-09-07 13:07:12 -07:00
// Create declaration
2014-09-09 00:29:01 +02:00
IDirect3DVertexDeclaration9 * pHardwareVertexDecl = nullptr ;
2017-02-05 20:36:00 +01:00
HRESULT hr = device_ - > CreateVertexDeclaration ( VertexElements , & pHardwareVertexDecl ) ;
2014-08-22 21:27:13 +02:00
if ( FAILED ( hr ) ) {
2014-09-13 12:27:20 +02:00
ERROR_LOG ( G3D , " Failed to create vertex declaration! " ) ;
pHardwareVertexDecl = nullptr ;
2014-08-22 21:27:13 +02:00
}
2013-09-01 08:38:40 +02:00
// Add it to map
2017-08-20 11:30:19 +02:00
vertexDeclMap_ . Insert ( pspFmt , pHardwareVertexDecl ) ;
2014-09-07 13:07:12 -07:00
return pHardwareVertexDecl ;
2013-09-01 08:38:40 +02:00
}
2013-08-21 11:10:56 +02:00
}
2016-04-10 10:21:48 +02:00
void DrawEngineDX9 : : MarkUnreliable ( VertexArrayInfoDX9 * vai ) {
2014-09-14 13:50:57 -07:00
vai - > status = VertexArrayInfoDX9 : : VAI_UNRELIABLE ;
if ( vai - > vbo ) {
vai - > vbo - > Release ( ) ;
vai - > vbo = nullptr ;
}
if ( vai - > ebo ) {
vai - > ebo - > Release ( ) ;
vai - > ebo = nullptr ;
2013-08-17 11:23:51 +02:00
}
}
2016-04-10 10:21:48 +02:00
void DrawEngineDX9 : : ClearTrackedVertexArrays ( ) {
2022-08-16 21:48:54 +02:00
vai_ . Iterate ( [ & ] ( uint32_t hash , VertexArrayInfoDX9 * vai ) {
2017-08-20 11:30:19 +02:00
delete vai ;
} ) ;
vai_ . Clear ( ) ;
2013-08-17 11:23:51 +02:00
}
2016-04-10 10:21:48 +02:00
void DrawEngineDX9 : : DecimateTrackedVertexArrays ( ) {
2013-08-20 18:47:11 +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 ;
int unreliableLeft = VAI_UNRELIABLE_KILL_MAX ;
2022-08-16 21:48:54 +02:00
vai_ . Iterate ( [ & ] ( uint32_t hash , VertexArrayInfoDX9 * vai ) {
2014-09-14 13:50:57 -07:00
bool kill ;
2017-08-20 11:30:19 +02:00
if ( vai - > status = = VertexArrayInfoDX9 : : VAI_UNRELIABLE ) {
2014-09-14 13:50:57 -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-14 13:50:57 -07:00
} else {
2017-08-20 11:30:19 +02:00
kill = vai - > lastFrame < threshold ;
2014-09-14 13:50:57 -07:00
}
if ( kill ) {
2017-08-20 11:30:19 +02:00
delete vai ;
vai_ . Remove ( hash ) ;
2014-09-14 13:50:57 -07:00
}
2017-08-20 11:30:19 +02:00
} ) ;
2017-12-02 18:27:18 -08:00
vai_ . Maintain ( ) ;
2013-08-17 11:23:51 +02:00
// Enable if you want to see vertex decoders in the log output. Need a better way.
#if 0
char buffer [ 16384 ] ;
for ( std : : map < u32 , VertexDecoder * > : : iterator dec = decoderMap_ . begin ( ) ; dec ! = decoderMap_ . end ( ) ; + + dec ) {
char * ptr = buffer ;
ptr + = dec - > second - > ToString ( ptr ) ;
2013-08-23 17:24:51 +02:00
// *ptr++ = '\n';
2013-09-10 22:35:38 +02:00
NOTICE_LOG ( G3D , buffer ) ;
2013-08-17 11:23:51 +02:00
}
# endif
}
2013-09-15 12:46:14 +02:00
VertexArrayInfoDX9 : : ~ VertexArrayInfoDX9 ( ) {
2013-08-17 11:23:51 +02:00
if ( vbo ) {
vbo - > Release ( ) ;
}
if ( ebo ) {
ebo - > Release ( ) ;
}
}
2017-01-21 17:45:53 +01:00
static uint32_t SwapRB ( uint32_t c ) {
return ( c & 0xFF00FF00 ) | ( ( c > > 16 ) & 0xFF ) | ( ( c < < 16 ) & 0xFF0000 ) ;
}
2020-05-24 20:57:59 +02:00
void DrawEngineDX9 : : BeginFrame ( ) {
2022-08-05 21:11:33 +02:00
gpuStats . numTrackedVertexArrays = ( int ) vai_ . size ( ) ;
2020-05-24 20:57:59 +02:00
DecimateTrackedVertexArrays ( ) ;
lastRenderStepId_ = - 1 ;
}
2022-11-24 10:38:49 +01:00
// In D3D, we're synchronous and state carries over so all we reset here on a new step is the viewport/scissor.
2022-12-01 19:15:38 +01:00
void DrawEngineDX9 : : Invalidate ( InvalidationCallbackFlags flags ) {
if ( flags & InvalidationCallbackFlags : : RENDER_PASS_STATE ) {
2022-11-24 10:38:49 +01:00
gstate_c . Dirty ( DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS ) ;
}
}
2014-10-18 11:26:51 +02:00
// The inline wrapper in the header checks for numDrawCalls == 0
2016-04-10 10:21:48 +02:00
void DrawEngineDX9 : : DoFlush ( ) {
2022-08-05 21:11:33 +02: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 ;
2022-10-02 20:44:35 -07:00
} else if ( gstate . getTextureAddress ( 0 ) = = ( gstate . getFrameBufRawAddress ( ) | 0x04000000 ) ) {
2022-08-05 21:11:33 +02:00
// This catches the case of clearing a texture. (#10957)
gstate_c . Dirty ( DIRTY_TEXTURE_IMAGE ) ;
}
2013-09-04 11:19:36 +02:00
GEPrimitiveType prim = prevPrim_ ;
2013-08-17 11:23:51 +02:00
2022-08-05 21:11:33 +02:00
// Always use software for flat shading to fix the provoking index.
bool tess = gstate_c . submitType = = SubmitType : : HW_BEZIER | | gstate_c . submitType = = SubmitType : : HW_SPLINE ;
bool useHWTransform = CanUseHardwareTransform ( prim ) & & ( tess | | gstate . getShadeMode ( ) ! = GE_SHADE_FLAT ) ;
2013-08-20 18:47:11 +02:00
2022-08-05 21:11:33 +02:00
if ( useHWTransform ) {
2014-09-17 22:03:44 +02:00
LPDIRECT3DVERTEXBUFFER9 vb_ = NULL ;
LPDIRECT3DINDEXBUFFER9 ib_ = NULL ;
2013-08-21 11:10:56 +02:00
2014-09-17 22:03:44 +02:00
int vertexCount = 0 ;
int maxIndex = 0 ;
bool useElements = true ;
2013-08-23 17:24:51 +02:00
2014-09-17 22:03:44 +02:00
// Cannot cache vertex data with morph enabled.
bool useCache = g_Config . bVertexCache & & ! ( lastVType_ & GE_VTYPE_MORPHCOUNT_MASK ) ;
2018-04-10 11:50:24 +02:00
// Also avoid caching when software skinning.
2022-11-06 08:40:54 -08:00
if ( decOptions_ . applySkinInDecode & & ( lastVType_ & GE_VTYPE_WEIGHT_MASK ) )
2014-09-17 22:03:44 +02:00
useCache = false ;
2014-09-13 01:01:54 +02:00
2014-09-17 22:03:44 +02:00
if ( useCache ) {
2017-02-04 11:37:24 +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
VertexArrayInfoDX9 * vai = vai_ . Get ( id ) ;
if ( ! vai ) {
2014-09-17 22:03:44 +02:00
vai = new VertexArrayInfoDX9 ( ) ;
2017-08-20 11:30:19 +02:00
vai_ . Insert ( id , vai ) ;
2014-09-17 22:03:44 +02:00
}
switch ( vai - > status ) {
case VertexArrayInfoDX9 : : VAI_NEW :
{
// Haven't seen this one before.
2020-08-27 20:37:49 -07:00
uint64_t dataHash = ComputeHash ( ) ;
2014-09-17 22:03:44 +02:00
vai - > hash = dataHash ;
vai - > minihash = ComputeMiniHash ( ) ;
vai - > status = VertexArrayInfoDX9 : : VAI_HASHING ;
vai - > drawsUntilNextFullHash = 0 ;
2017-11-19 12:38:52 +01:00
DecodeVerts ( decoded ) ; // writes to indexGen
2014-09-17 22:03:44 +02:00
vai - > numVerts = indexGen . VertexCount ( ) ;
vai - > prim = indexGen . Prim ( ) ;
vai - > maxIndex = indexGen . MaxIndex ( ) ;
vai - > flags = gstate_c . vertexFullAlpha ? VAI_FLAG_VERTEXFULLALPHA : 0 ;
goto rotateVBO ;
2013-08-23 17:24:51 +02:00
}
2014-09-17 22:03:44 +02: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 VertexArrayInfoDX9 : : VAI_HASHING :
{
vai - > numDraws + + ;
if ( vai - > lastFrame ! = gpuStats . numFlips ) {
vai - > numFrames + + ;
}
if ( vai - > drawsUntilNextFullHash = = 0 ) {
// Let's try to skip a full hash if mini would fail.
const u32 newMiniHash = ComputeMiniHash ( ) ;
2020-08-27 20:37:49 -07:00
uint64_t newHash = vai - > hash ;
2014-09-17 22:03:44 +02:00
if ( newMiniHash = = vai - > minihash ) {
newHash = ComputeHash ( ) ;
}
if ( newMiniHash ! = vai - > minihash | | newHash ! = vai - > hash ) {
MarkUnreliable ( vai ) ;
2017-11-19 12:38:52 +01:00
DecodeVerts ( decoded ) ;
2014-09-17 22:03:44 +02:00
goto rotateVBO ;
}
if ( vai - > numVerts > 64 ) {
// exponential backoff up to 16 draws, then every 24
vai - > drawsUntilNextFullHash = std : : min ( 24 , vai - > numFrames ) ;
} else {
// Lower numbers seem much more likely to change.
vai - > drawsUntilNextFullHash = 0 ;
}
// TODO: tweak
//if (vai->numFrames > 1000) {
// vai->status = VertexArrayInfo::VAI_RELIABLE;
//}
} else {
vai - > drawsUntilNextFullHash - - ;
u32 newMiniHash = ComputeMiniHash ( ) ;
if ( newMiniHash ! = vai - > minihash ) {
MarkUnreliable ( vai ) ;
2017-11-19 12:38:52 +01:00
DecodeVerts ( decoded ) ;
2014-09-17 22:03:44 +02:00
goto rotateVBO ;
}
}
if ( vai - > vbo = = 0 ) {
2017-11-19 12:38:52 +01:00
DecodeVerts ( decoded ) ;
2013-08-23 17:24:51 +02:00
vai - > numVerts = indexGen . VertexCount ( ) ;
vai - > prim = indexGen . Prim ( ) ;
2013-11-15 14:24:25 +01:00
vai - > maxIndex = indexGen . MaxIndex ( ) ;
2014-09-09 01:03:08 -07:00
vai - > flags = gstate_c . vertexFullAlpha ? VAI_FLAG_VERTEXFULLALPHA : 0 ;
2014-09-17 22:03:44 +02:00
useElements = ! indexGen . SeenOnlyPurePrims ( ) ;
if ( ! useElements & & indexGen . PureCount ( ) ) {
vai - > numVerts = indexGen . PureCount ( ) ;
2013-08-23 17:24:51 +02:00
}
2015-09-13 11:09:21 -07:00
2020-07-19 17:47:02 +02:00
_dbg_assert_msg_ ( gstate_c . vertBounds . minV > = gstate_c . vertBounds . maxV , " Should not have checked UVs when caching. " ) ;
2015-09-13 11:09:21 -07:00
2014-09-18 00:40:25 +02:00
void * pVb ;
u32 size = dec_ - > GetDecVtxFmt ( ) . stride * indexGen . MaxIndex ( ) ;
2017-02-05 20:36:00 +01:00
device_ - > CreateVertexBuffer ( size , D3DUSAGE_WRITEONLY , 0 , D3DPOOL_DEFAULT , & vai - > vbo , NULL ) ;
2014-09-18 00:40:25 +02:00
vai - > vbo - > Lock ( 0 , size , & pVb , 0 ) ;
memcpy ( pVb , decoded , size ) ;
vai - > vbo - > Unlock ( ) ;
2014-09-17 22:03:44 +02:00
if ( useElements ) {
void * pIb ;
2014-10-18 11:26:51 +02:00
u32 size = sizeof ( short ) * indexGen . VertexCount ( ) ;
2017-02-05 20:36:00 +01:00
device_ - > CreateIndexBuffer ( size , D3DUSAGE_WRITEONLY , D3DFMT_INDEX16 , D3DPOOL_DEFAULT , & vai - > ebo , NULL ) ;
2014-09-17 22:03:44 +02:00
vai - > ebo - > Lock ( 0 , size , & pIb , 0 ) ;
memcpy ( pIb , decIndex , size ) ;
vai - > ebo - > Unlock ( ) ;
2013-08-23 17:24:51 +02:00
} else {
2014-09-17 22:03:44 +02:00
vai - > ebo = 0 ;
2013-08-23 17:24:51 +02:00
}
2014-09-17 22:03:44 +02:00
} else {
2013-08-23 17:24:51 +02:00
gpuStats . numCachedDrawCalls + + ;
2014-09-17 22:03:44 +02:00
useElements = vai - > ebo ? true : false ;
2013-08-23 17:24:51 +02:00
gpuStats . numCachedVertsDrawn + = vai - > numVerts ;
2014-09-09 01:03:08 -07:00
gstate_c . vertexFullAlpha = vai - > flags & VAI_FLAG_VERTEXFULLALPHA ;
2013-08-23 17:24:51 +02:00
}
2014-09-17 22:03:44 +02:00
vb_ = vai - > vbo ;
ib_ = vai - > ebo ;
vertexCount = vai - > numVerts ;
maxIndex = vai - > maxIndex ;
prim = static_cast < GEPrimitiveType > ( vai - > prim ) ;
break ;
2013-08-23 17:24:51 +02:00
}
2014-09-17 22:03:44 +02:00
// Reliable - we don't even bother hashing anymore. Right now we don't go here until after a very long time.
case VertexArrayInfoDX9 : : VAI_RELIABLE :
{
vai - > numDraws + + ;
if ( vai - > lastFrame ! = gpuStats . numFlips ) {
vai - > numFrames + + ;
}
gpuStats . numCachedDrawCalls + + ;
gpuStats . numCachedVertsDrawn + = vai - > numVerts ;
vb_ = vai - > vbo ;
ib_ = vai - > ebo ;
vertexCount = vai - > numVerts ;
maxIndex = vai - > maxIndex ;
prim = static_cast < GEPrimitiveType > ( vai - > prim ) ;
gstate_c . vertexFullAlpha = vai - > flags & VAI_FLAG_VERTEXFULLALPHA ;
break ;
2013-08-23 17:24:51 +02:00
}
2014-09-17 22:03:44 +02:00
case VertexArrayInfoDX9 : : VAI_UNRELIABLE :
{
vai - > numDraws + + ;
if ( vai - > lastFrame ! = gpuStats . numFlips ) {
vai - > numFrames + + ;
2014-08-22 21:27:13 +02:00
}
2017-11-19 12:38:52 +01:00
DecodeVerts ( decoded ) ;
2014-09-17 22:03:44 +02:00
goto rotateVBO ;
2013-08-23 17:24:51 +02:00
}
}
2014-09-17 22:03:44 +02:00
vai - > lastFrame = gpuStats . numFlips ;
2013-08-21 11:10:56 +02:00
} else {
2017-11-19 12:38:52 +01:00
DecodeVerts ( decoded ) ;
2014-09-17 22:03:44 +02:00
rotateVBO :
2013-08-23 17:24:51 +02:00
gpuStats . numUncachedVertsDrawn + = indexGen . VertexCount ( ) ;
2014-09-17 22:03:44 +02:00
useElements = ! indexGen . SeenOnlyPurePrims ( ) ;
vertexCount = indexGen . VertexCount ( ) ;
maxIndex = indexGen . MaxIndex ( ) ;
if ( ! useElements & & indexGen . PureCount ( ) ) {
vertexCount = indexGen . PureCount ( ) ;
2014-09-13 13:53:04 +02:00
}
2014-09-17 22:03:44 +02:00
prim = indexGen . Prim ( ) ;
2013-08-21 11:10:56 +02:00
}
2013-08-17 11:23:51 +02:00
2014-09-17 22:03:44 +02: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-09-22 00:18:46 -07:00
2022-08-05 21:11:33 +02:00
if ( textureNeedsApply ) {
textureCache_ - > ApplyTexture ( ) ;
}
ApplyDrawState ( prim ) ;
2015-03-17 22:07:09 -07:00
ApplyDrawStateLate ( ) ;
2022-08-05 21:11:33 +02:00
2022-12-14 22:48:17 +01:00
VSShader * vshader = shaderManager_ - > ApplyShader ( true , useHWTessellation_ , dec_ , decOptions_ . expandAllWeightsToFloat , decOptions_ . applySkinInDecode , pipelineState_ ) ;
2014-09-17 22:03:44 +02:00
IDirect3DVertexDeclaration9 * pHardwareVertexDecl = SetupDecFmtForDraw ( vshader , dec_ - > GetDecVtxFmt ( ) , dec_ - > VertexType ( ) ) ;
if ( pHardwareVertexDecl ) {
2017-02-05 20:36:00 +01:00
device_ - > SetVertexDeclaration ( pHardwareVertexDecl ) ;
2014-09-17 22:03:44 +02:00
if ( vb_ = = NULL ) {
if ( useElements ) {
2020-01-26 15:28:54 +01:00
device_ - > DrawIndexedPrimitiveUP ( d3d_prim [ prim ] , 0 , maxIndex + 1 , D3DPrimCount ( d3d_prim [ prim ] , vertexCount ) , decIndex , D3DFMT_INDEX16 , decoded , dec_ - > GetDecVtxFmt ( ) . stride ) ;
2014-09-17 22:03:44 +02:00
} else {
2020-01-26 15:28:54 +01:00
device_ - > DrawPrimitiveUP ( d3d_prim [ prim ] , D3DPrimCount ( d3d_prim [ prim ] , vertexCount ) , decoded , dec_ - > GetDecVtxFmt ( ) . stride ) ;
2014-09-17 22:03:44 +02:00
}
} else {
2017-02-05 20:36:00 +01:00
device_ - > SetStreamSource ( 0 , vb_ , 0 , dec_ - > GetDecVtxFmt ( ) . stride ) ;
2014-09-17 22:03:44 +02:00
if ( useElements ) {
2017-02-05 20:36:00 +01:00
device_ - > SetIndices ( ib_ ) ;
2014-09-17 22:03:44 +02:00
2020-01-26 15:28:54 +01:00
device_ - > DrawIndexedPrimitive ( d3d_prim [ prim ] , 0 , 0 , maxIndex + 1 , 0 , D3DPrimCount ( d3d_prim [ prim ] , vertexCount ) ) ;
2014-09-17 22:03:44 +02:00
} else {
2020-01-26 15:28:54 +01:00
device_ - > DrawPrimitive ( d3d_prim [ prim ] , 0 , D3DPrimCount ( d3d_prim [ prim ] , vertexCount ) ) ;
2014-09-17 22:03:44 +02:00
}
}
}
} else {
2022-11-09 07:07:39 -08:00
if ( ! decOptions_ . applySkinInDecode ) {
decOptions_ . applySkinInDecode = true ;
lastVType_ | = ( 1 < < 26 ) ;
dec_ = GetVertexDecoder ( lastVType_ ) ;
}
2017-11-19 12:38:52 +01:00
DecodeVerts ( decoded ) ;
2014-09-17 22:03:44 +02: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 ) ;
}
gpuStats . numUncachedVertsDrawn + = indexGen . VertexCount ( ) ;
prim = indexGen . Prim ( ) ;
// Undo the strip optimization, not supported by the SW code yet.
if ( prim = = GE_PRIM_TRIANGLE_STRIP )
prim = GE_PRIM_TRIANGLES ;
2015-01-04 18:00:59 +01:00
VERBOSE_LOG ( G3D , " Flush prim %i SW! %i verts in one go " , prim , indexGen . VertexCount ( ) ) ;
2014-09-17 22:03:44 +02:00
u16 * inds = decIndex ;
2017-12-02 09:58:13 +01:00
SoftwareTransformResult result { } ;
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 ;
2021-01-24 16:07:13 -08:00
params . allowSeparateAlphaClear = false ;
2018-04-28 16:32:09 -07:00
params . provokeFlatFirst = true ;
2021-10-23 11:29:19 -07:00
params . flippedY = false ;
2021-10-23 14:20:44 -07:00
params . usesHalfZ = true ;
2016-03-12 13:37:08 -08:00
2021-10-30 17:30:05 -07:00
// We need correct viewport values in gstate_c already.
if ( gstate_c . IsDirty ( DIRTY_VIEWPORTSCISSOR_STATE ) ) {
ViewportAndScissor vpAndScissor ;
ConvertViewportAndScissor ( framebufferManager_ - > UseBufferedRendering ( ) ,
framebufferManager_ - > GetRenderWidth ( ) , framebufferManager_ - > GetRenderHeight ( ) ,
framebufferManager_ - > GetTargetBufferWidth ( ) , framebufferManager_ - > GetTargetBufferHeight ( ) ,
vpAndScissor ) ;
2022-08-20 14:16:55 -07:00
UpdateCachedViewportState ( vpAndScissor ) ;
2021-10-30 17:30:05 -07:00
}
2015-01-15 23:58:07 +01:00
int maxIndex = indexGen . MaxIndex ( ) ;
2020-05-08 00:26:41 -07:00
SoftwareTransform swTransform ( params ) ;
2021-10-23 11:59:34 -07:00
// Half pixel offset hack.
float xOffset = - 1.0f / gstate_c . curRTRenderWidth ;
float yOffset = 1.0f / gstate_c . curRTRenderHeight ;
2022-08-22 21:30:10 -07:00
const Lin : : Vec3 trans ( gstate_c . vpXOffset + xOffset , - gstate_c . vpYOffset + yOffset , gstate_c . vpZOffset * 0.5f + 0.5f ) ;
2021-10-23 11:59:34 -07:00
const Lin : : Vec3 scale ( gstate_c . vpWidthScale , gstate_c . vpHeightScale , gstate_c . vpDepthScale * 0.5f ) ;
swTransform . SetProjMatrix ( gstate . projMatrix , gstate_c . vpWidth < 0 , gstate_c . vpHeight > 0 , trans , scale ) ;
2020-05-08 00:26:41 -07:00
swTransform . Decode ( prim , dec_ - > VertexType ( ) , dec_ - > GetDecVtxFmt ( ) , maxIndex , & result ) ;
2022-11-09 20:34:29 -08:00
// Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values.
// Games sometimes expect exact matches (see #12626, for example) for equal comparisons.
if ( result . action = = SW_CLEAR & & everUsedEqualDepth_ & & gstate . isClearModeDepthMask ( ) & & result . depth > 0.0f & & result . depth < 1.0f )
result . action = SW_NOT_READY ;
2020-05-08 00:26:41 -07:00
if ( result . action = = SW_NOT_READY ) {
swTransform . DetectOffsetTexture ( maxIndex ) ;
}
2014-09-17 22:03:44 +02:00
2022-08-05 21:11:33 +02:00
if ( textureNeedsApply )
textureCache_ - > ApplyTexture ( ) ;
ApplyDrawState ( prim ) ;
if ( result . action = = SW_NOT_READY )
swTransform . BuildDrawingParams ( prim , indexGen . VertexCount ( ) , dec_ - > VertexType ( ) , inds , maxIndex , & result ) ;
2020-05-23 00:25:39 -07:00
if ( result . setSafeSize )
framebufferManager_ - > SetSafeSize ( result . safeWidth , result . safeHeight ) ;
2015-09-13 06:53:25 -07:00
ApplyDrawStateLate ( ) ;
2022-08-05 21:11:33 +02:00
2022-12-14 22:48:17 +01:00
VSShader * vshader = shaderManager_ - > ApplyShader ( false , false , dec_ , decOptions_ . expandAllWeightsToFloat , true , pipelineState_ ) ;
2015-09-13 06:53:25 -07:00
2014-09-17 22:03:44 +02:00
if ( result . action = = SW_DRAW_PRIMITIVES ) {
if ( result . setStencil ) {
2022-07-24 21:40:04 +02:00
dxstate . stencilFunc . set ( D3DCMP_ALWAYS ) ;
dxstate . stencilRef . set ( result . stencilValue ) ;
dxstate . stencilCompareMask . set ( 255 ) ;
2014-09-17 22:03:44 +02:00
}
// TODO: Add a post-transform cache here for multi-RECTANGLES only.
// Might help for text drawing.
2017-02-05 20:36:00 +01:00
device_ - > SetVertexDeclaration ( transformedVertexDecl_ ) ;
2020-05-08 00:26:41 -07:00
if ( result . drawIndexed ) {
device_ - > DrawIndexedPrimitiveUP ( d3d_prim [ prim ] , 0 , maxIndex , D3DPrimCount ( d3d_prim [ prim ] , result . drawNumTrans ) , inds , D3DFMT_INDEX16 , result . drawBuffer , sizeof ( TransformedVertex ) ) ;
2014-09-17 22:03:44 +02:00
} else {
2020-05-08 00:26:41 -07:00
device_ - > DrawPrimitiveUP ( d3d_prim [ prim ] , D3DPrimCount ( d3d_prim [ prim ] , result . drawNumTrans ) , result . drawBuffer , sizeof ( TransformedVertex ) ) ;
2014-09-17 22:03:44 +02:00
}
} else if ( result . action = = SW_CLEAR ) {
u32 clearColor = result . color ;
float clearDepth = result . depth ;
int mask = gstate . isClearModeColorMask ( ) ? D3DCLEAR_TARGET : 0 ;
if ( gstate . isClearModeAlphaMask ( ) ) mask | = D3DCLEAR_STENCIL ;
if ( gstate . isClearModeDepthMask ( ) ) mask | = D3DCLEAR_ZBUFFER ;
if ( mask & D3DCLEAR_TARGET ) {
2015-07-26 22:38:40 +02:00
framebufferManager_ - > SetColorUpdated ( gstate_c . skipDrawReason ) ;
2014-09-17 22:03:44 +02:00
}
2017-02-05 20:36:00 +01:00
device_ - > Clear ( 0 , NULL , mask , SwapRB ( clearColor ) , clearDepth , clearColor > > 24 ) ;
2016-05-19 20:55:34 -07:00
2022-10-17 08:27:49 +02:00
if ( gstate_c . Use ( GPU_USE_CLEAR_RAM_HACK ) & & gstate . isClearModeColorMask ( ) & & ( gstate . isClearModeAlphaMask ( ) | | gstate_c . framebufFormat = = GE_FORMAT_565 ) ) {
2017-02-13 01:22:55 +01:00
int scissorX1 = gstate . getScissorX1 ( ) ;
int scissorY1 = gstate . getScissorY1 ( ) ;
2020-05-23 00:25:39 -07:00
int scissorX2 = gstate . getScissorX2 ( ) + 1 ;
int scissorY2 = gstate . getScissorY2 ( ) + 1 ;
2017-04-09 15:10:07 -07:00
framebufferManager_ - > ApplyClearToMemory ( scissorX1 , scissorY1 , scissorX2 , scissorY2 , clearColor ) ;
2016-09-18 19:40:44 -07:00
}
2014-09-17 22:03:44 +02:00
}
2022-11-06 08:55:07 -08:00
decOptions_ . applySkinInDecode = g_Config . bSoftwareSkinning ;
2014-09-17 22:03:44 +02:00
}
2023-01-04 17:10:56 +01:00
gpuStats . numFlushes + + ;
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
2014-09-17 22:03:44 +02:00
indexGen . Reset ( ) ;
decodedVerts_ = 0 ;
numDrawCalls = 0 ;
2017-06-02 12:03:46 +02:00
vertexCountInDrawCalls_ = 0 ;
2014-09-17 22:03:44 +02:00
decodeCounter_ = 0 ;
dcid_ = 0 ;
gstate_c . vertexFullAlpha = true ;
2015-07-26 22:38:40 +02:00
framebufferManager_ - > SetColorUpdated ( gstate_c . skipDrawReason ) ;
2014-09-17 22:03:44 +02: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 ( ) ;
2013-08-17 11:23:51 +02:00
}
2014-08-24 14:21:35 +02:00
2018-09-29 13:39:02 +09:00
void TessellationDataTransferDX9 : : SendDataToShader ( const SimpleVertex * const * points , int size_u , int size_v , u32 vertType , const Spline : : Weight2D & weights ) {
2018-07-13 18:35:44 +09:00
// TODO
2017-01-10 14:41:01 +09:00
}