2017-02-08 17:07:34 +00: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/.
# include "base/logging.h"
# include "base/timeutil.h"
# include "Common/MemoryUtil.h"
# include "Core/MemMap.h"
# include "Core/Host.h"
# include "Core/System.h"
# include "Core/Reporting.h"
# include "Core/Config.h"
# include "Core/CoreTiming.h"
# include "GPU/Math3D.h"
# include "GPU/GPUState.h"
# include "GPU/ge_constants.h"
# include "GPU/Common/TextureDecoder.h"
# include "GPU/Common/SplineCommon.h"
# include "GPU/Common/TransformCommon.h"
# include "GPU/Common/VertexDecoderCommon.h"
# include "GPU/Common/SoftwareTransformCommon.h"
# include "GPU/D3D11/TextureCacheD3D11.h"
# include "GPU/D3D11/DrawEngineD3D11.h"
# include "GPU/D3D11/ShaderManagerD3D11.h"
# include "GPU/D3D11/GPU_D3D11.h"
const D3D11_PRIMITIVE_TOPOLOGY glprim [ 8 ] = {
D3D11_PRIMITIVE_TOPOLOGY_POINTLIST ,
D3D11_PRIMITIVE_TOPOLOGY_LINELIST ,
D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP ,
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ,
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP ,
D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED , // Fans not supported
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST , // Need expansion - though we could do it with geom shaders in most cases
} ;
enum {
TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof ( TransformedVertex )
} ;
# define VERTEXCACHE_DECIMATION_INTERVAL 17
enum { VAI_KILL_AGE = 120 , VAI_UNRELIABLE_KILL_AGE = 240 , VAI_UNRELIABLE_KILL_MAX = 4 } ;
2017-02-09 12:57:24 +00:00
enum {
VERTEX_PUSH_SIZE = 1024 * 1024 * 16 ,
INDEX_PUSH_SIZE = 1024 * 1024 * 4 ,
} ;
2017-02-08 17:07:34 +00:00
static const D3D11_INPUT_ELEMENT_DESC TransformedVertexElements [ ] = {
{ " POSITION " , 0 , DXGI_FORMAT_R32G32B32A32_FLOAT , 0 , 0 , D3D11_INPUT_PER_VERTEX_DATA , 0 } ,
{ " TEXCOORD " , 0 , DXGI_FORMAT_R32G32B32_FLOAT , 0 , 16 , D3D11_INPUT_PER_VERTEX_DATA , 0 } ,
{ " COLOR " , 0 , DXGI_FORMAT_R8G8B8A8_UNORM , 0 , 28 , D3D11_INPUT_PER_VERTEX_DATA , 0 } ,
{ " COLOR " , 1 , DXGI_FORMAT_R8G8B8A8_UNORM , 0 , 32 , D3D11_INPUT_PER_VERTEX_DATA , 0 } ,
} ;
2017-02-10 09:26:18 +00:00
DrawEngineD3D11 : : DrawEngineD3D11 ( Draw : : DrawContext * draw , ID3D11Device * device , ID3D11DeviceContext * context )
: draw_ ( draw ) ,
device_ ( device ) ,
2017-02-08 17:07:34 +00:00
context_ ( context ) ,
decodedVerts_ ( 0 ) ,
prevPrim_ ( GE_PRIM_INVALID ) ,
lastVType_ ( - 1 ) ,
shaderManager_ ( 0 ) ,
textureCache_ ( 0 ) ,
framebufferManager_ ( 0 ) ,
numDrawCalls ( 0 ) ,
vertexCountInDrawCalls ( 0 ) ,
decodeCounter_ ( 0 ) ,
dcid_ ( 0 ) ,
fboTexNeedBind_ ( false ) ,
fboTexBound_ ( false ) {
decOptions_ . expandAllWeightsToFloat = true ;
decOptions_ . expand8BitNormalsToFloat = true ;
decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL ;
// 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.
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 ) ;
transformed = ( TransformedVertex * ) AllocateMemoryPages ( TRANSFORMED_VERTEX_BUFFER_SIZE , MEM_PROT_READ | MEM_PROT_WRITE ) ;
transformedExpanded = ( TransformedVertex * ) AllocateMemoryPages ( 3 * TRANSFORMED_VERTEX_BUFFER_SIZE , MEM_PROT_READ | MEM_PROT_WRITE ) ;
indexGen . Setup ( decIndex ) ;
InitDeviceObjects ( ) ;
tessDataTransfer = new TessellationDataTransferD3D11 ( ) ;
2017-02-09 12:57:24 +00:00
// Vertex pushing buffers.
pushVerts_ = new PushBufferD3D11 ( device , VERTEX_PUSH_SIZE , D3D11_BIND_VERTEX_BUFFER ) ;
pushInds_ = new PushBufferD3D11 ( device , INDEX_PUSH_SIZE , D3D11_BIND_INDEX_BUFFER ) ;
2017-02-08 17:07:34 +00:00
}
DrawEngineD3D11 : : ~ DrawEngineD3D11 ( ) {
2017-02-09 12:57:24 +00:00
delete pushVerts_ ;
delete pushInds_ ;
2017-02-10 09:26:18 +00:00
for ( auto decl = inputLayoutMap_ . begin ( ) ; decl ! = inputLayoutMap_ . end ( ) ; + + decl ) {
if ( decl - > second ) {
decl - > second - > Release ( ) ;
}
}
for ( auto & depth : depthStencilCache_ ) {
depth . second - > Release ( ) ;
}
for ( auto & blend : blendCache_ ) {
blend . second - > Release ( ) ;
2017-02-08 17:07:34 +00:00
}
DestroyDeviceObjects ( ) ;
FreeMemoryPages ( decoded , DECODED_VERTEX_BUFFER_SIZE ) ;
FreeMemoryPages ( decIndex , DECODED_INDEX_BUFFER_SIZE ) ;
FreeMemoryPages ( splineBuffer , SPLINE_BUFFER_SIZE ) ;
FreeMemoryPages ( transformed , TRANSFORMED_VERTEX_BUFFER_SIZE ) ;
FreeMemoryPages ( transformedExpanded , 3 * TRANSFORMED_VERTEX_BUFFER_SIZE ) ;
delete tessDataTransfer ;
}
void DrawEngineD3D11 : : InitDeviceObjects ( ) {
}
void DrawEngineD3D11 : : DestroyDeviceObjects ( ) {
ClearTrackedVertexArrays ( ) ;
}
struct DeclTypeInfo {
DXGI_FORMAT type ;
const char * name ;
} ;
static const DeclTypeInfo VComp [ ] = {
{ DXGI_FORMAT_UNKNOWN , " NULL " } , // DEC_NONE,
{ DXGI_FORMAT_R32_FLOAT , " D3DDECLTYPE_FLOAT1 " } , // DEC_FLOAT_1,
{ DXGI_FORMAT_R32G32_FLOAT , " D3DDECLTYPE_FLOAT2 " } , // DEC_FLOAT_2,
{ DXGI_FORMAT_R32G32B32_FLOAT , " D3DDECLTYPE_FLOAT3 " } , // DEC_FLOAT_3,
{ DXGI_FORMAT_R32G32B32A32_FLOAT , " D3DDECLTYPE_FLOAT4 " } , // DEC_FLOAT_4,
{ DXGI_FORMAT_R8G8B8A8_SNORM , " UNUSED " } , // DEC_S8_3,
{ DXGI_FORMAT_R16G16B16A16_SNORM , " D3DDECLTYPE_SHORT4N " } , // DEC_S16_3,
{ DXGI_FORMAT_R8G8B8A8_UNORM , " D3DDECLTYPE_UBYTE4N " } , // DEC_U8_1,
{ DXGI_FORMAT_R8G8B8A8_UNORM , " D3DDECLTYPE_UBYTE4N " } , // DEC_U8_2,
{ DXGI_FORMAT_R8G8B8A8_UNORM , " D3DDECLTYPE_UBYTE4N " } , // DEC_U8_3,
{ DXGI_FORMAT_R8G8B8A8_UNORM , " D3DDECLTYPE_UBYTE4N " } , // DEC_U8_4,
{ DXGI_FORMAT_UNKNOWN , " UNUSED_DEC_U16_1 " } , // DEC_U16_1,
{ DXGI_FORMAT_UNKNOWN , " UNUSED_DEC_U16_2 " } , // DEC_U16_2,
{ DXGI_FORMAT_R16G16B16A16_UNORM , " D3DDECLTYPE_USHORT4N " } , // DEC_U16_3,
{ DXGI_FORMAT_R16G16B16A16_UNORM , " D3DDECLTYPE_USHORT4N " } , // DEC_U16_4,
{ DXGI_FORMAT_UNKNOWN , " UNUSED_DEC_U8A_2 " } , // DEC_U8A_2,
{ DXGI_FORMAT_UNKNOWN , " UNUSED_DEC_U16A_2 " } , // DEC_U16A_2,
} ;
static void VertexAttribSetup ( D3D11_INPUT_ELEMENT_DESC * VertexElement , u8 fmt , u8 offset , const char * semantic , u8 semantic_index = 0 ) {
memset ( VertexElement , 0 , sizeof ( D3D11_INPUT_ELEMENT_DESC ) ) ;
VertexElement - > AlignedByteOffset = offset ;
VertexElement - > Format = VComp [ fmt ] . type ;
VertexElement - > SemanticName = semantic ;
VertexElement - > SemanticIndex = semantic_index ;
}
ID3D11InputLayout * DrawEngineD3D11 : : SetupDecFmtForDraw ( D3D11VertexShader * vshader , const DecVtxFormat & decFmt , u32 pspFmt ) {
2017-02-10 09:26:18 +00:00
// TODO: Instead of one for each vshader, we can reduce it to one for each type of shader
// that reads TEXCOORD or not, etc. Not sure if worth it.
InputLayoutKey key { pspFmt , vshader } ;
auto vertexDeclCached = inputLayoutMap_ . find ( key ) ;
if ( vertexDeclCached = = inputLayoutMap_ . end ( ) ) {
2017-02-08 17:07:34 +00:00
D3D11_INPUT_ELEMENT_DESC VertexElements [ 8 ] ;
D3D11_INPUT_ELEMENT_DESC * VertexElement = & VertexElements [ 0 ] ;
// Vertices Elements orders
// WEIGHT
if ( decFmt . w0fmt ! = 0 ) {
VertexAttribSetup ( VertexElement , decFmt . w0fmt , decFmt . w0off , " TEXCOORD " , 1 ) ;
VertexElement + + ;
}
if ( decFmt . w1fmt ! = 0 ) {
VertexAttribSetup ( VertexElement , decFmt . w1fmt , decFmt . w1off , " TEXCOORD " , 2 ) ;
VertexElement + + ;
}
// TC
if ( decFmt . uvfmt ! = 0 ) {
VertexAttribSetup ( VertexElement , decFmt . uvfmt , decFmt . uvoff , " TEXCOORD " , 0 ) ;
VertexElement + + ;
}
// COLOR
if ( decFmt . c0fmt ! = 0 ) {
VertexAttribSetup ( VertexElement , decFmt . c0fmt , decFmt . c0off , " COLOR " , 0 ) ;
VertexElement + + ;
}
// Never used ?
if ( decFmt . c1fmt ! = 0 ) {
VertexAttribSetup ( VertexElement , decFmt . c1fmt , decFmt . c1off , " COLOR " , 1 ) ;
VertexElement + + ;
}
// NORMAL
if ( decFmt . nrmfmt ! = 0 ) {
VertexAttribSetup ( VertexElement , decFmt . nrmfmt , decFmt . nrmoff , " NORMAL " , 0 ) ;
VertexElement + + ;
}
// POSITION
// Always
VertexAttribSetup ( VertexElement , decFmt . posfmt , decFmt . posoff , " POSITION " , 0 ) ;
VertexElement + + ;
// Create declaration
ID3D11InputLayout * inputLayout = nullptr ;
HRESULT hr = device_ - > CreateInputLayout ( VertexElements , VertexElement - VertexElements , vshader - > bytecode ( ) . data ( ) , vshader - > bytecode ( ) . size ( ) , & inputLayout ) ;
if ( FAILED ( hr ) ) {
ERROR_LOG ( G3D , " Failed to create input layout! " ) ;
inputLayout = nullptr ;
}
// Add it to map
2017-02-10 09:26:18 +00:00
inputLayoutMap_ [ key ] = inputLayout ;
2017-02-08 17:07:34 +00:00
return inputLayout ;
} else {
// Set it from map
return vertexDeclCached - > second ;
}
}
void DrawEngineD3D11 : : SetupVertexDecoder ( u32 vertType ) {
SetupVertexDecoderInternal ( vertType ) ;
}
inline void DrawEngineD3D11 : : SetupVertexDecoderInternal ( u32 vertType ) {
// As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it
// into the top of the verttype where there are unused bits.
const u32 vertTypeID = ( vertType & 0xFFFFFF ) | ( gstate . getUVGenMode ( ) < < 24 ) ;
// If vtype has changed, setup the vertex decoder.
if ( vertTypeID ! = lastVType_ ) {
dec_ = GetVertexDecoder ( vertTypeID ) ;
lastVType_ = vertTypeID ;
}
}
void DrawEngineD3D11 : : SubmitPrim ( void * verts , void * inds , GEPrimitiveType prim , int vertexCount , u32 vertType , int * bytesRead ) {
if ( ! indexGen . PrimCompatible ( prevPrim_ , prim ) | | numDrawCalls > = MAX_DEFERRED_DRAW_CALLS | | vertexCountInDrawCalls + vertexCount > VERTEX_BUFFER_MAX )
Flush ( ) ;
// TODO: Is this the right thing to do?
if ( prim = = GE_PRIM_KEEP_PREVIOUS ) {
prim = prevPrim_ ! = GE_PRIM_INVALID ? prevPrim_ : GE_PRIM_POINTS ;
} else {
prevPrim_ = prim ;
}
SetupVertexDecoderInternal ( vertType ) ;
* bytesRead = vertexCount * dec_ - > VertexSize ( ) ;
if ( ( vertexCount < 2 & & prim > 0 ) | | ( vertexCount < 3 & & prim > 2 & & prim ! = GE_PRIM_RECTANGLES ) )
return ;
DeferredDrawCall & dc = drawCalls [ numDrawCalls ] ;
dc . verts = verts ;
dc . inds = inds ;
dc . vertType = vertType ;
dc . indexType = ( vertType & GE_VTYPE_IDX_MASK ) > > GE_VTYPE_IDX_SHIFT ;
dc . prim = prim ;
dc . vertexCount = vertexCount ;
u32 dhash = dcid_ ;
dhash ^ = ( u32 ) ( uintptr_t ) verts ;
dhash = __rotl ( dhash , 13 ) ;
dhash ^ = ( u32 ) ( uintptr_t ) inds ;
dhash = __rotl ( dhash , 13 ) ;
dhash ^ = ( u32 ) vertType ;
dhash = __rotl ( dhash , 13 ) ;
dhash ^ = ( u32 ) vertexCount ;
dhash = __rotl ( dhash , 13 ) ;
dhash ^ = ( u32 ) prim ;
dcid_ = dhash ;
if ( inds ) {
GetIndexBounds ( inds , vertexCount , vertType , & dc . indexLowerBound , & dc . indexUpperBound ) ;
} else {
dc . indexLowerBound = 0 ;
dc . indexUpperBound = vertexCount - 1 ;
}
uvScale [ numDrawCalls ] = gstate_c . uv ;
numDrawCalls + + ;
vertexCountInDrawCalls + = vertexCount ;
if ( g_Config . bSoftwareSkinning & & ( vertType & GE_VTYPE_WEIGHT_MASK ) ) {
DecodeVertsStep ( ) ;
decodeCounter_ + + ;
}
if ( prim = = GE_PRIM_RECTANGLES & & ( gstate . getTextureAddress ( 0 ) & 0x3FFFFFFF ) = = ( gstate . getFrameBufAddress ( ) & 0x3FFFFFFF ) ) {
// Rendertarget == texture?
if ( ! g_Config . bDisableSlowFramebufEffects ) {
gstate_c . Dirty ( DIRTY_TEXTURE_PARAMS ) ;
Flush ( ) ;
}
}
}
void DrawEngineD3D11 : : DecodeVerts ( ) {
const UVScale origUV = gstate_c . uv ;
for ( ; decodeCounter_ < numDrawCalls ; decodeCounter_ + + ) {
gstate_c . uv = uvScale [ decodeCounter_ ] ;
DecodeVertsStep ( ) ;
}
gstate_c . uv = origUV ;
// Sanity check
if ( indexGen . Prim ( ) < 0 ) {
ERROR_LOG_REPORT ( G3D , " DecodeVerts: Failed to deduce prim: %i " , indexGen . Prim ( ) ) ;
// Force to points (0)
indexGen . AddPrim ( GE_PRIM_POINTS , 0 ) ;
}
}
void DrawEngineD3D11 : : DecodeVertsStep ( ) {
const int i = decodeCounter_ ;
const DeferredDrawCall & dc = drawCalls [ i ] ;
indexGen . SetIndex ( decodedVerts_ ) ;
int indexLowerBound = dc . indexLowerBound , indexUpperBound = dc . indexUpperBound ;
u32 indexType = dc . indexType ;
void * inds = dc . inds ;
if ( indexType = = GE_VTYPE_IDX_NONE > > GE_VTYPE_IDX_SHIFT ) {
// Decode the verts and apply morphing. Simple.
dec_ - > DecodeVerts ( decoded + decodedVerts_ * ( int ) dec_ - > GetDecVtxFmt ( ) . stride ,
dc . verts , indexLowerBound , indexUpperBound ) ;
decodedVerts_ + = indexUpperBound - indexLowerBound + 1 ;
indexGen . AddPrim ( dc . prim , dc . vertexCount ) ;
} else {
// It's fairly common that games issue long sequences of PRIM calls, with differing
// inds pointer but the same base vertex pointer. We'd like to reuse vertices between
// these as much as possible, so we make sure here to combine as many as possible
// into one nice big drawcall, sharing data.
// 1. Look ahead to find the max index, only looking as "matching" drawcalls.
// Expand the lower and upper bounds as we go.
int lastMatch = i ;
const int total = numDrawCalls ;
for ( int j = i + 1 ; j < total ; + + j ) {
if ( drawCalls [ j ] . verts ! = dc . verts )
break ;
if ( memcmp ( & uvScale [ j ] , & uvScale [ i ] , sizeof ( uvScale [ 0 ] ) ) ! = 0 )
break ;
indexLowerBound = std : : min ( indexLowerBound , ( int ) drawCalls [ j ] . indexLowerBound ) ;
indexUpperBound = std : : max ( indexUpperBound , ( int ) drawCalls [ j ] . indexUpperBound ) ;
lastMatch = j ;
}
// 2. Loop through the drawcalls, translating indices as we go.
switch ( indexType ) {
case GE_VTYPE_IDX_8BIT > > GE_VTYPE_IDX_SHIFT :
for ( int j = i ; j < = lastMatch ; j + + ) {
indexGen . TranslatePrim ( drawCalls [ j ] . prim , drawCalls [ j ] . vertexCount , ( const u8 * ) drawCalls [ j ] . inds , indexLowerBound ) ;
}
break ;
case GE_VTYPE_IDX_16BIT > > GE_VTYPE_IDX_SHIFT :
for ( int j = i ; j < = lastMatch ; j + + ) {
indexGen . TranslatePrim ( drawCalls [ j ] . prim , drawCalls [ j ] . vertexCount , ( const u16_le * ) drawCalls [ j ] . inds , indexLowerBound ) ;
}
break ;
case GE_VTYPE_IDX_32BIT > > GE_VTYPE_IDX_SHIFT :
for ( int j = i ; j < = lastMatch ; j + + ) {
indexGen . TranslatePrim ( drawCalls [ j ] . prim , drawCalls [ j ] . vertexCount , ( const u32_le * ) drawCalls [ j ] . inds , indexLowerBound ) ;
}
break ;
}
const int vertexCount = indexUpperBound - indexLowerBound + 1 ;
// This check is a workaround for Pangya Fantasy Golf, which sends bogus index data when switching items in "My Room" sometimes.
if ( decodedVerts_ + vertexCount > VERTEX_BUFFER_MAX ) {
return ;
}
// 3. Decode that range of vertex data.
dec_ - > DecodeVerts ( decoded + decodedVerts_ * ( int ) dec_ - > GetDecVtxFmt ( ) . stride ,
dc . verts , indexLowerBound , indexUpperBound ) ;
decodedVerts_ + = vertexCount ;
// 4. Advance indexgen vertex counter.
indexGen . Advance ( vertexCount ) ;
decodeCounter_ = lastMatch ;
}
}
inline u32 ComputeMiniHashRange ( const void * ptr , size_t sz ) {
// Switch to u32 units.
const u32 * p = ( const u32 * ) ptr ;
sz > > = 2 ;
if ( sz > 100 ) {
size_t step = sz / 4 ;
u32 hash = 0 ;
for ( size_t i = 0 ; i < sz ; i + = step ) {
hash + = DoReliableHash32 ( p + i , 100 , 0x3A44B9C4 ) ;
}
return hash ;
} else {
return p [ 0 ] + p [ sz - 1 ] ;
}
}
u32 DrawEngineD3D11 : : ComputeMiniHash ( ) {
u32 fullhash = 0 ;
const int vertexSize = dec_ - > GetDecVtxFmt ( ) . stride ;
const int indexSize = IndexSize ( dec_ - > VertexType ( ) ) ;
int step ;
if ( numDrawCalls < 3 ) {
step = 1 ;
} else if ( numDrawCalls < 8 ) {
step = 4 ;
} else {
step = numDrawCalls / 8 ;
}
for ( int i = 0 ; i < numDrawCalls ; i + = step ) {
const DeferredDrawCall & dc = drawCalls [ i ] ;
if ( ! dc . inds ) {
fullhash + = ComputeMiniHashRange ( dc . verts , vertexSize * dc . vertexCount ) ;
} else {
int indexLowerBound = dc . indexLowerBound , indexUpperBound = dc . indexUpperBound ;
fullhash + = ComputeMiniHashRange ( ( const u8 * ) dc . verts + vertexSize * indexLowerBound , vertexSize * ( indexUpperBound - indexLowerBound ) ) ;
fullhash + = ComputeMiniHashRange ( dc . inds , indexSize * dc . vertexCount ) ;
}
}
return fullhash ;
}
void DrawEngineD3D11 : : MarkUnreliable ( VertexArrayInfoD3D11 * vai ) {
vai - > status = VertexArrayInfoD3D11 : : VAI_UNRELIABLE ;
if ( vai - > vbo ) {
vai - > vbo - > Release ( ) ;
vai - > vbo = nullptr ;
}
if ( vai - > ebo ) {
vai - > ebo - > Release ( ) ;
vai - > ebo = nullptr ;
}
}
ReliableHashType DrawEngineD3D11 : : ComputeHash ( ) {
ReliableHashType fullhash = 0 ;
const int vertexSize = dec_ - > GetDecVtxFmt ( ) . stride ;
const int indexSize = IndexSize ( dec_ - > VertexType ( ) ) ;
// TODO: Add some caps both for numDrawCalls and num verts to check?
// It is really very expensive to check all the vertex data so often.
for ( int i = 0 ; i < numDrawCalls ; i + + ) {
const DeferredDrawCall & dc = drawCalls [ i ] ;
if ( ! dc . inds ) {
fullhash + = DoReliableHash ( ( const char * ) dc . verts , vertexSize * dc . vertexCount , 0x1DE8CAC4 ) ;
} else {
int indexLowerBound = dc . indexLowerBound , indexUpperBound = dc . indexUpperBound ;
int j = i + 1 ;
int lastMatch = i ;
while ( j < numDrawCalls ) {
if ( drawCalls [ j ] . verts ! = dc . verts )
break ;
indexLowerBound = std : : min ( indexLowerBound , ( int ) dc . indexLowerBound ) ;
indexUpperBound = std : : max ( indexUpperBound , ( int ) dc . indexUpperBound ) ;
lastMatch = j ;
j + + ;
}
// This could get seriously expensive with sparse indices. Need to combine hashing ranges the same way
// we do when drawing.
fullhash + = DoReliableHash ( ( const char * ) dc . verts + vertexSize * indexLowerBound ,
vertexSize * ( indexUpperBound - indexLowerBound ) , 0x029F3EE1 ) ;
// Hm, we will miss some indices when combining above, but meh, it should be fine.
fullhash + = DoReliableHash ( ( const char * ) dc . inds , indexSize * dc . vertexCount , 0x955FD1CA ) ;
i = lastMatch ;
}
}
if ( uvScale ) {
fullhash + = DoReliableHash ( & uvScale [ 0 ] , sizeof ( uvScale [ 0 ] ) * numDrawCalls , 0x0123e658 ) ;
}
return fullhash ;
}
void DrawEngineD3D11 : : ClearTrackedVertexArrays ( ) {
for ( auto vai = vai_ . begin ( ) ; vai ! = vai_ . end ( ) ; vai + + ) {
delete vai - > second ;
}
vai_ . clear ( ) ;
}
2017-02-10 09:26:18 +00:00
void DrawEngineD3D11 : : BeginFrame ( ) {
pushVerts_ - > Reset ( ) ;
pushInds_ - > Reset ( ) ;
2017-02-08 17:07:34 +00:00
if ( - - decimationCounter_ < = 0 ) {
decimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL ;
} else {
return ;
}
const int threshold = gpuStats . numFlips - VAI_KILL_AGE ;
const int unreliableThreshold = gpuStats . numFlips - VAI_UNRELIABLE_KILL_AGE ;
int unreliableLeft = VAI_UNRELIABLE_KILL_MAX ;
for ( auto iter = vai_ . begin ( ) ; iter ! = vai_ . end ( ) ; ) {
bool kill ;
if ( iter - > second - > status = = VertexArrayInfoD3D11 : : VAI_UNRELIABLE ) {
// We limit killing unreliable so we don't rehash too often.
kill = iter - > second - > lastFrame < unreliableThreshold & & - - unreliableLeft > = 0 ;
} else {
kill = iter - > second - > lastFrame < threshold ;
}
if ( kill ) {
delete iter - > second ;
vai_ . erase ( iter + + ) ;
} else {
+ + iter ;
}
}
// 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 ) ;
// *ptr++ = '\n';
NOTICE_LOG ( G3D , buffer ) ;
}
# endif
}
VertexArrayInfoD3D11 : : ~ VertexArrayInfoD3D11 ( ) {
if ( vbo ) {
vbo - > Release ( ) ;
}
if ( ebo ) {
ebo - > Release ( ) ;
}
}
static uint32_t SwapRB ( uint32_t c ) {
return ( c & 0xFF00FF00 ) | ( ( c > > 16 ) & 0xFF ) | ( ( c < < 16 ) & 0xFF0000 ) ;
}
// The inline wrapper in the header checks for numDrawCalls == 0
void DrawEngineD3D11 : : DoFlush ( ) {
gpuStats . numFlushes + + ;
gpuStats . numTrackedVertexArrays = ( int ) vai_ . size ( ) ;
// This is not done on every drawcall, we should collect vertex data
// until critical state changes. That's when we draw (flush).
GEPrimitiveType prim = prevPrim_ ;
ApplyDrawState ( prim ) ;
bool useHWTransform = CanUseHardwareTransform ( prim ) ;
if ( useHWTransform ) {
ID3D11Buffer * vb_ = nullptr ;
ID3D11Buffer * ib_ = nullptr ;
int vertexCount = 0 ;
int maxIndex = 0 ;
bool useElements = true ;
// Cannot cache vertex data with morph enabled.
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 ;
if ( useCache ) {
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
auto iter = vai_ . find ( id ) ;
VertexArrayInfoD3D11 * vai ;
if ( iter ! = vai_ . end ( ) ) {
// We've seen this before. Could have been a cached draw.
vai = iter - > second ;
} else {
vai = new VertexArrayInfoD3D11 ( ) ;
vai_ [ id ] = vai ;
}
switch ( vai - > status ) {
case VertexArrayInfoD3D11 : : VAI_NEW :
{
// Haven't seen this one before.
ReliableHashType dataHash = ComputeHash ( ) ;
vai - > hash = dataHash ;
vai - > minihash = ComputeMiniHash ( ) ;
vai - > status = VertexArrayInfoD3D11 : : VAI_HASHING ;
vai - > drawsUntilNextFullHash = 0 ;
DecodeVerts ( ) ; // writes to indexGen
vai - > numVerts = indexGen . VertexCount ( ) ;
vai - > prim = indexGen . Prim ( ) ;
vai - > maxIndex = indexGen . MaxIndex ( ) ;
vai - > flags = gstate_c . vertexFullAlpha ? VAI11_FLAG_VERTEXFULLALPHA : 0 ;
goto rotateVBO ;
}
// Hashing - still gaining confidence about the buffer.
// But if we get this far it's likely to be worth creating a vertex buffer.
case VertexArrayInfoD3D11 : : 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 ( ) ;
ReliableHashType newHash = vai - > hash ;
if ( newMiniHash = = vai - > minihash ) {
newHash = ComputeHash ( ) ;
}
if ( newMiniHash ! = vai - > minihash | | newHash ! = vai - > hash ) {
MarkUnreliable ( vai ) ;
DecodeVerts ( ) ;
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 ) ;
DecodeVerts ( ) ;
goto rotateVBO ;
}
}
if ( vai - > vbo = = 0 ) {
DecodeVerts ( ) ;
vai - > numVerts = indexGen . VertexCount ( ) ;
vai - > prim = indexGen . Prim ( ) ;
vai - > maxIndex = indexGen . MaxIndex ( ) ;
vai - > flags = gstate_c . vertexFullAlpha ? VAI11_FLAG_VERTEXFULLALPHA : 0 ;
2017-02-12 11:12:15 +00:00
useElements = ! indexGen . SeenOnlyPurePrims ( ) | | prim = = GE_PRIM_TRIANGLE_FAN ;
2017-02-08 17:07:34 +00:00
if ( ! useElements & & indexGen . PureCount ( ) ) {
vai - > numVerts = indexGen . PureCount ( ) ;
}
_dbg_assert_msg_ ( G3D , gstate_c . vertBounds . minV > = gstate_c . vertBounds . maxV , " Should not have checked UVs when caching. " ) ;
// TODO: Combine these two into one buffer?
u32 size = dec_ - > GetDecVtxFmt ( ) . stride * indexGen . MaxIndex ( ) ;
2017-02-09 23:01:56 +00:00
D3D11_BUFFER_DESC desc { size , D3D11_USAGE_IMMUTABLE , D3D11_BIND_VERTEX_BUFFER , 0 } ;
2017-02-08 17:07:34 +00:00
D3D11_SUBRESOURCE_DATA data { decoded } ;
device_ - > CreateBuffer ( & desc , & data , & vai - > vbo ) ;
if ( useElements ) {
u32 size = sizeof ( short ) * indexGen . VertexCount ( ) ;
2017-02-09 23:01:56 +00:00
D3D11_BUFFER_DESC desc { size , D3D11_USAGE_IMMUTABLE , D3D11_BIND_INDEX_BUFFER , 0 } ;
2017-02-10 09:26:18 +00:00
D3D11_SUBRESOURCE_DATA data { decIndex } ;
2017-02-08 17:07:34 +00:00
device_ - > CreateBuffer ( & desc , & data , & vai - > ebo ) ;
} else {
vai - > ebo = 0 ;
}
} else {
gpuStats . numCachedDrawCalls + + ;
useElements = vai - > ebo ? true : false ;
gpuStats . numCachedVertsDrawn + = vai - > numVerts ;
gstate_c . vertexFullAlpha = vai - > flags & VAI11_FLAG_VERTEXFULLALPHA ;
}
vb_ = vai - > vbo ;
ib_ = vai - > ebo ;
vertexCount = vai - > numVerts ;
maxIndex = vai - > maxIndex ;
prim = static_cast < GEPrimitiveType > ( vai - > prim ) ;
break ;
}
// Reliable - we don't even bother hashing anymore. Right now we don't go here until after a very long time.
case VertexArrayInfoD3D11 : : 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 & VAI11_FLAG_VERTEXFULLALPHA ;
break ;
}
case VertexArrayInfoD3D11 : : VAI_UNRELIABLE :
{
vai - > numDraws + + ;
if ( vai - > lastFrame ! = gpuStats . numFlips ) {
vai - > numFrames + + ;
}
DecodeVerts ( ) ;
goto rotateVBO ;
}
}
vai - > lastFrame = gpuStats . numFlips ;
} else {
DecodeVerts ( ) ;
rotateVBO :
gpuStats . numUncachedVertsDrawn + = indexGen . VertexCount ( ) ;
2017-02-12 11:12:15 +00:00
useElements = ! indexGen . SeenOnlyPurePrims ( ) | | prim = = GE_PRIM_TRIANGLE_FAN ;
2017-02-08 17:07:34 +00:00
vertexCount = indexGen . VertexCount ( ) ;
maxIndex = indexGen . MaxIndex ( ) ;
if ( ! useElements & & indexGen . PureCount ( ) ) {
vertexCount = indexGen . PureCount ( ) ;
}
prim = indexGen . Prim ( ) ;
}
VERBOSE_LOG ( G3D , " Flush prim %i! %i verts in one go " , prim , vertexCount ) ;
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 ) ;
}
ApplyDrawStateLate ( false , 0 ) ;
D3D11VertexShader * vshader ;
D3D11FragmentShader * fshader ;
shaderManager_ - > GetShaders ( prim , lastVType_ , & vshader , & fshader , useHWTransform ) ;
2017-02-10 09:26:18 +00:00
ID3D11InputLayout * inputLayout = SetupDecFmtForDraw ( vshader , dec_ - > GetDecVtxFmt ( ) , dec_ - > VertexType ( ) ) ;
2017-02-09 23:01:56 +00:00
context_ - > PSSetShader ( fshader - > GetShader ( ) , nullptr , 0 ) ;
context_ - > VSSetShader ( vshader - > GetShader ( ) , nullptr , 0 ) ;
2017-02-12 11:02:13 +00:00
shaderManager_ - > UpdateUniforms ( ) ;
shaderManager_ - > BindUniforms ( ) ;
2017-02-08 17:07:34 +00:00
2017-02-10 09:26:18 +00:00
context_ - > IASetInputLayout ( inputLayout ) ;
UINT stride = dec_ - > GetDecVtxFmt ( ) . stride ;
context_ - > IASetPrimitiveTopology ( glprim [ prim ] ) ;
2017-02-08 17:07:34 +00:00
if ( ! vb_ ) {
// Push!
2017-02-10 09:26:18 +00:00
UINT vOffset ;
int vSize = ( maxIndex + 1 ) * dec_ - > GetDecVtxFmt ( ) . stride ;
uint8_t * vptr = pushVerts_ - > BeginPush ( context_ , & vOffset , vSize ) ;
memcpy ( vptr , decoded , vSize ) ;
pushVerts_ - > EndPush ( context_ ) ;
ID3D11Buffer * buf = pushVerts_ - > Buf ( ) ;
context_ - > IASetVertexBuffers ( 0 , 1 , & buf , & stride , & vOffset ) ;
2017-02-08 17:07:34 +00:00
if ( useElements ) {
2017-02-10 09:26:18 +00:00
UINT iOffset ;
2017-02-10 10:25:24 +00:00
int iSize = 2 * indexGen . VertexCount ( ) ;
2017-02-10 09:26:18 +00:00
uint8_t * iptr = pushInds_ - > BeginPush ( context_ , & iOffset , iSize ) ;
memcpy ( iptr , decIndex , iSize ) ;
pushInds_ - > EndPush ( context_ ) ;
context_ - > IASetIndexBuffer ( pushInds_ - > Buf ( ) , DXGI_FORMAT_R16_UINT , iOffset ) ;
context_ - > DrawIndexed ( vertexCount , 0 , 0 ) ;
2017-02-08 17:07:34 +00:00
} else {
2017-02-10 09:26:18 +00:00
context_ - > Draw ( vertexCount , 0 ) ;
2017-02-08 17:07:34 +00:00
}
} else {
UINT offset = 0 ;
context_ - > IASetVertexBuffers ( 0 , 1 , & vb_ , & stride , & offset ) ;
if ( useElements ) {
context_ - > IASetIndexBuffer ( ib_ , DXGI_FORMAT_R16_UINT , 0 ) ;
context_ - > DrawIndexed ( vertexCount , 0 , 0 ) ;
} else {
context_ - > Draw ( vertexCount , 0 ) ;
}
}
} else {
DecodeVerts ( ) ;
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 ;
VERBOSE_LOG ( G3D , " Flush prim %i SW! %i verts in one go " , prim , indexGen . VertexCount ( ) ) ;
int numTrans = 0 ;
bool drawIndexed = false ;
u16 * inds = decIndex ;
TransformedVertex * drawBuffer = NULL ;
SoftwareTransformResult result ;
memset ( & result , 0 , sizeof ( result ) ) ;
SoftwareTransformParams params ;
memset ( & params , 0 , sizeof ( params ) ) ;
params . decoded = decoded ;
params . transformed = transformed ;
params . transformedExpanded = transformedExpanded ;
params . fbman = framebufferManager_ ;
params . texCache = textureCache_ ;
params . allowSeparateAlphaClear = true ;
int maxIndex = indexGen . MaxIndex ( ) ;
SoftwareTransform (
prim , indexGen . VertexCount ( ) ,
dec_ - > VertexType ( ) , inds , GE_VTYPE_IDX_16BIT , dec_ - > GetDecVtxFmt ( ) ,
maxIndex , drawBuffer , numTrans , drawIndexed , & params , & result ) ;
ApplyDrawStateLate ( result . setStencil , result . stencilValue ) ;
2017-02-10 09:26:18 +00:00
if ( result . action = = SW_DRAW_PRIMITIVES ) {
2017-02-08 17:07:34 +00:00
const int vertexSize = sizeof ( transformed [ 0 ] ) ;
2017-02-12 12:55:49 +00:00
D3D11VertexShader * vshader ;
D3D11FragmentShader * fshader ;
shaderManager_ - > GetShaders ( prim , lastVType_ , & vshader , & fshader , false ) ;
context_ - > PSSetShader ( fshader - > GetShader ( ) , nullptr , 0 ) ;
context_ - > VSSetShader ( vshader - > GetShader ( ) , nullptr , 0 ) ;
shaderManager_ - > UpdateUniforms ( ) ;
shaderManager_ - > BindUniforms ( ) ;
2017-02-10 09:26:18 +00:00
// We really do need a vertex layout for each vertex shader (or at least check its ID bits for what inputs it uses)!
// Some vertex shaders ignore one of the inputs, and then the layout created from it will lack it, which will be a problem for others.
InputLayoutKey key { 0xFFFFFFFF , vshader } ; // Let's use 0xFFFFFFFF to signify TransformedVertex
auto iter = inputLayoutMap_ . find ( key ) ;
ID3D11InputLayout * layout ;
if ( iter = = inputLayoutMap_ . end ( ) ) {
device_ - > CreateInputLayout ( TransformedVertexElements , ARRAY_SIZE ( TransformedVertexElements ) , vshader - > bytecode ( ) . data ( ) , vshader - > bytecode ( ) . size ( ) , & layout ) ;
inputLayoutMap_ [ key ] = layout ;
} else {
layout = iter - > second ;
2017-02-08 17:07:34 +00:00
}
2017-02-10 09:26:18 +00:00
context_ - > IASetInputLayout ( layout ) ;
UINT stride = sizeof ( TransformedVertex ) ;
UINT vOffset = 0 ;
2017-02-10 10:25:24 +00:00
int vSize = maxIndex * stride ;
2017-02-10 09:26:18 +00:00
uint8_t * vptr = pushVerts_ - > BeginPush ( context_ , & vOffset , vSize ) ;
memcpy ( vptr , drawBuffer , vSize ) ;
pushVerts_ - > EndPush ( context_ ) ;
ID3D11Buffer * buf = pushVerts_ - > Buf ( ) ;
context_ - > IASetVertexBuffers ( 0 , 1 , & buf , & stride , & vOffset ) ;
2017-02-08 17:07:34 +00:00
if ( drawIndexed ) {
2017-02-10 09:26:18 +00:00
UINT iOffset ;
2017-02-12 12:55:49 +00:00
int iSize = sizeof ( uint16_t ) * numTrans ;
2017-02-10 09:26:18 +00:00
uint8_t * iptr = pushInds_ - > BeginPush ( context_ , & iOffset , iSize ) ;
memcpy ( iptr , inds , iSize ) ;
pushInds_ - > EndPush ( context_ ) ;
context_ - > IASetIndexBuffer ( pushInds_ - > Buf ( ) , DXGI_FORMAT_R16_UINT , iOffset ) ;
2017-02-10 10:25:24 +00:00
context_ - > DrawIndexed ( numTrans , 0 , 0 ) ;
2017-02-08 17:07:34 +00:00
} else {
context_ - > Draw ( numTrans , 0 ) ;
}
2017-02-10 09:26:18 +00:00
} else if ( result . action = = SW_CLEAR ) {
2017-02-08 17:07:34 +00:00
u32 clearColor = result . color ;
float clearDepth = result . depth ;
2017-02-10 09:32:32 +00:00
uint32_t clearFlag = 0 ;
2017-02-08 17:07:34 +00:00
2017-02-10 09:32:32 +00:00
if ( gstate . isClearModeColorMask ( ) ) clearFlag | = Draw : : COLOR ;
if ( gstate . isClearModeAlphaMask ( ) ) clearFlag | = Draw : : STENCIL ;
if ( gstate . isClearModeDepthMask ( ) ) clearFlag | = Draw : : DEPTH ;
2017-02-08 17:07:34 +00:00
if ( clearColor ) {
framebufferManager_ - > SetColorUpdated ( gstate_c . skipDrawReason ) ;
}
2017-02-10 09:32:32 +00:00
if ( clearFlag & Draw : : DEPTH ) {
2017-02-08 17:07:34 +00:00
framebufferManager_ - > SetDepthUpdated ( ) ;
}
int colorMask = 0 ;
if ( clearColor )
colorMask | = 7 ;
2017-02-10 09:32:32 +00:00
if ( clearFlag & Draw : : STENCIL ) {
2017-02-08 17:07:34 +00:00
colorMask | = 8 ;
}
context_ - > OMSetBlendState ( stockD3D11 . blendStateDisabledWithColorMask [ colorMask ] , nullptr , 0xFFFFFFFF ) ;
2017-02-10 09:32:32 +00:00
uint8_t clearStencil = clearColor > > 24 ;
draw_ - > Clear ( clearFlag , clearColor , clearDepth , clearStencil ) ;
2017-02-08 17:07:34 +00:00
int scissorX2 = gstate . getScissorX2 ( ) + 1 ;
int scissorY2 = gstate . getScissorY2 ( ) + 1 ;
framebufferManager_ - > SetSafeSize ( scissorX2 , scissorY2 ) ;
if ( g_Config . bBlockTransferGPU & & ( gstate_c . featureFlags & GPU_USE_CLEAR_RAM_HACK ) & & gstate . isClearModeColorMask ( ) & & ( gstate . isClearModeAlphaMask ( ) | | gstate . FrameBufFormat ( ) = = GE_FORMAT_565 ) ) {
2017-02-10 09:26:18 +00:00
int scissorX1 = gstate . getScissorX1 ( ) ;
int scissorY1 = gstate . getScissorY1 ( ) ;
2017-02-08 17:07:34 +00:00
ApplyClearToMemory ( scissorX1 , scissorY1 , scissorX2 , scissorY2 , clearColor ) ;
}
2017-02-10 09:26:18 +00:00
}
2017-02-08 17:07:34 +00:00
}
gpuStats . numDrawCalls + = numDrawCalls ;
gpuStats . numVertsSubmitted + = vertexCountInDrawCalls ;
indexGen . Reset ( ) ;
decodedVerts_ = 0 ;
numDrawCalls = 0 ;
vertexCountInDrawCalls = 0 ;
decodeCounter_ = 0 ;
dcid_ = 0 ;
prevPrim_ = GE_PRIM_INVALID ;
gstate_c . vertexFullAlpha = true ;
framebufferManager_ - > SetColorUpdated ( gstate_c . skipDrawReason ) ;
// Now seems as good a time as any to reset the min/max coords, which we may examine later.
gstate_c . vertBounds . minU = 512 ;
gstate_c . vertBounds . minV = 512 ;
gstate_c . vertBounds . maxU = 0 ;
gstate_c . vertBounds . maxV = 0 ;
host - > GPUNotifyDraw ( ) ;
}
void DrawEngineD3D11 : : Resized ( ) {
decJitCache_ - > Clear ( ) ;
lastVType_ = - 1 ;
dec_ = NULL ;
for ( auto iter = decoderMap_ . begin ( ) ; iter ! = decoderMap_ . end ( ) ; iter + + ) {
delete iter - > second ;
}
decoderMap_ . clear ( ) ;
}
bool DrawEngineD3D11 : : IsCodePtrVertexDecoder ( const u8 * ptr ) const {
return decJitCache_ - > IsInSpace ( ptr ) ;
}
void DrawEngineD3D11 : : TessellationDataTransferD3D11 : : SendDataToShader ( const float * pos , const float * tex , const float * col , int size , bool hasColor , bool hasTexCoords )
{
}