/////////////////////////////////////////////////////////////////////////////// // // ## ###### // ###### ### // ## ############### Shark 3D Engine (www.shark3d.com) // ########## # # # // ######## Copyright (c) 1996-2006 Spinor GmbH. // ######### # # # All rights reserved. // ## ########## // ## // /////////////////////////////////////////////////////////////////////////////// //@cpp #include "drv_d3d9_progutil.h" #include "drv_d3d9_settings.h" #include "drv_d3d9_util.h" #include "util/base/util_charutil.h" #include "util/stream/util_textstreampos.h" #include "sys/core/sys_endian.h" #include #include /////////////////////////////////////////////////////////////////////////////// bool s3d_CDrvD3d9ProgUtil::ParseMajorMinor( int &Major, int &Minor, s3d_CSysIntps CapLen, const s3d_CSysChar *CapStart) { if(CapLen == 0) { Major = 0; Minor = 0; return true; } s3d_CSysIntps Parse = 0; if(!ParseNum(Major, CapLen, CapStart, Parse)) return false; if(CapStart[Parse] != 'x') return false; Parse++; if(!ParseNum(Minor, CapLen, CapStart, Parse)) return false; if(Parse < CapLen) return false; return true; } bool s3d_CDrvD3d9ProgUtil::ParseNum( int &Val, s3d_CSysIntps CapLen, const s3d_CSysChar *CapStart, s3d_CSysIntps &Parse) { bool Ok = false; Val = 0; while(Parse < CapLen && s3d_CUtilCharUtil::IsDigit(CapStart[Parse])) { Ok = true; Val = (Val * 10) + (CapStart[Parse] - '0'); Parse++; } return Ok; } int s3d_CDrvD3d9ProgUtil::CompVer( int MajorA, int MinorA, int MajorB, int MinorB) { if(MajorA > MajorB) return 1; if(MajorA < MajorB) return -1; if(MinorA > MinorB) return 1; if(MinorA < MinorB) return -1; return 0; } bool s3d_CDrvD3d9ProgUtil::IsVersAllowed( int MaxMajor, int MaxMinor, s3d_CUtilStr_cr ReqVer) { int ReqMajor, ReqMinor; bool Allowed = s3d_CDrvD3d9ProgUtil::ParseMajorMinor( ReqMajor, ReqMinor, ReqVer.GetLen(), ReqVer.GetChars()); if(Allowed) { Allowed = s3d_CDrvD3d9ProgUtil::CompVer( MaxMajor, MaxMinor, ReqMajor, ReqMinor) >= 0; } return Allowed; } s3d_CUtilStr s3d_CDrvD3d9ProgUtil::StrOfVers(DWORD Vers) { s3d_CUtilStrBuf VersBuf; // 0xFFFExxyy d3d vertex shader // 0xFFFFxxyy d3d pixel shader DWORD ShaderType = Vers >> 16; if(ShaderType == 0xFFFE) VersBuf.Append("vs_"); else if(ShaderType == 0xFFFF) VersBuf.Append("ps_"); else return ""; int Major = D3DSHADER_VERSION_MAJOR(Vers); int Minor = D3DSHADER_VERSION_MINOR(Vers); VersBuf.AppendInt(Major); VersBuf.Append("_"); VersBuf.AppendInt(Minor); return VersBuf; } s3d_CUtilStr s3d_CDrvD3d9ProgUtil::GenProfileString( s3d_CUtilStr_cr Vers, s3d_CUtilStr_cr Type) { int Major, Minor; ParseMajorMinor(Major, Minor, Vers.GetLen(), Vers.GetChars()); s3d_CUtilStr Profile = Type + "_" + s3d_CUtilStrUtil::StrOfInt(Major) + "_" + s3d_CUtilStrUtil::StrOfInt(Minor); return Profile; } void s3d_CDrvD3d9ProgUtil::D3dMarcoArrayOfPreprocArray( s3d_CUtilOwnArray &D3dMacroArray, s3d_CLibStreamPreproState *PreproState) { int nPredDef = PreproState->m_MacroMap.GetCntInt(); int AllocCnt = nPredDef + 1; D3dMacroArray.Alloc(AllocCnt); LPD3DXMACRO D3dMacro = D3dMacroArray; s3d_CLibStreamPreproMacroMap::CNode *MacroNode = PreproState->m_MacroMap.GetFirstNode(); int i; for(i = 0; i < nPredDef; i++) { s3d_CLibStreamPreproMacro *Macro = MacroNode->m_Data.m_Val; D3dMacro->Name = MacroNode->m_Data.m_Key.GetChars(); D3dMacro->Definition = Macro->m_Content.GetChars(); D3dMacro++; MacroNode = MacroNode->GetNext(); } D3dMacro->Name = 0; D3dMacro->Definition = 0; } void s3d_CDrvD3d9ProgUtil::GetProgDecl( const s3d_CDrvD3d9ProgCtx *ProgCtx, s3d_CDrvD3d9ProgDecl &ProgDecl, s3d_CSysIntps FuncSize, const DWORD *FuncData) { ProgDecl.m_SemanticsCnt = 0; ProgDecl.m_SemanticArray.Reset(); if(!FuncData) return; UINT Count = 0; S3D_DRV_D3D9_CHECK( ProgCtx->m_Env, D3DXGetShaderInputSemantics( FuncData, 0, &Count)); if(Count <= 0) return; ProgDecl.m_SemanticArray.Alloc(Count); S3D_DRV_D3D9_CHECK( ProgCtx->m_Env, D3DXGetShaderInputSemantics( FuncData, ProgDecl.m_SemanticArray, &Count)); if(Count <= 0) { ProgDecl.m_SemanticArray.Reset(); return; } ProgDecl.m_SemanticsCnt = Count; ProgDecl.m_ProgUsage = s3d_CDrvD3d9ProgUtil::CalcProgUsage( ProgCtx, ProgDecl.m_SemanticsCnt, ProgDecl.m_SemanticArray); } int s3d_CDrvD3d9ProgUtil::CalcProgUsage( const s3d_CDrvD3d9ProgCtx *ProgCtx, s3d_CSysIntps SemanticsCnt, const D3DXSEMANTIC *SemanticArray) { if(!ProgCtx) return 0; if(!SemanticArray) return 0; int ProgUsage = 0; s3d_CSysIntps iSemantic; for(iSemantic = 0; iSemantic < SemanticsCnt; iSemantic++) { DWORD Usage = SemanticArray->Usage; DWORD UsageIdx = SemanticArray->UsageIndex; switch(Usage) { case D3DDECLUSAGE_BLENDWEIGHT: { ProgUsage |= s3d_CDrvD3d9Prog::Usage_BoneWgh; break; } case D3DDECLUSAGE_BLENDINDICES: { ProgUsage |= s3d_CDrvD3d9Prog::Usage_BoneSubscr; break; } /* case D3DDECLUSAGE_NORMAL: case D3DDECLUSAGE_TEXCOORD: case D3DDECLUSAGE_COLOR: case D3DDECLUSAGE_POSITION: case D3DDECLUSAGE_PSIZE: case D3DDECLUSAGE_TANGENT: case D3DDECLUSAGE_BINORMAL: case D3DDECLUSAGE_TESSFACTOR: case D3DDECLUSAGE_POSITIONT: case D3DDECLUSAGE_FOG: case D3DDECLUSAGE_DEPTH: case D3DDECLUSAGE_SAMPLE: */ default: break; } SemanticArray++; } return ProgUsage; } void s3d_CDrvD3d9ProgUtil::CalcVertBufDesc( const s3d_CDrvD3d9ProgCtx *ProgCtx, const s3d_CDrvGfxCharge *Charge, int VertProgUsage, const s3d_CDrvD3d9VertComprFmt *VertComprFmt, s3d_CDrvD3d9VertBufDesc &VertBufDesc) { VertBufDesc.Reset(); if(!Charge) return; bool NoDummyBoneVertexBuf = ProgCtx->m_D3dParam->m_NoDummyBoneVertexBuf; bool Complete = true; int VertBufFmtDecl = 0; s3d_CDrvGfxAttr *PointAttr = 0; s3d_CDrvGfxAttr *ColorAlphaAttr = 0; s3d_CDrvGfxAttr *NormalAttr = 0; s3d_CDrvGfxAttr *BoneWghAttr = 0; s3d_CDrvGfxAttr *BoneSubscrAttr = 0; s3d_CDrvGfxAttr *TexAttrArray[S3D_DRV_D3D9_MAX_ATTR_CNT]; int TexSlotCnt = 0; const s3d_CDrvDataTypeDesc *TexTypeDescArray[S3D_DRV_D3D9_MAX_ATTR_CNT]; BYTE TexSlotArray[S3D_DRV_D3D9_MAX_ATTR_CNT]; int iTex; for(iTex = 0; iTex < S3D_DRV_D3D9_MAX_ATTR_CNT; iTex++) { TexTypeDescArray[iTex] = 0; TexAttrArray[iTex] = 0; TexSlotArray[iTex] = 0; } int iAttr; for(iAttr = 0; iAttr < Charge->m_AttrCnt; iAttr++) { s3d_CDrvGfxAttr *Attr = &Charge->m_AttrArray[iAttr]; if(Attr->m_BankDyn) Complete = false; s3d_CDrvBankContent BankContent; s3d_DrvBankFetch( ProgCtx->m_MsgHandler, Charge->m_MainInfo, "attr", Attr->m_Bank, BankContent); int Slot = Attr->m_Slot; int Chan = Attr->m_Chan; switch(Chan) { case s3d_CDrvGfxEng::AttrChan_Generic: { if(s3d_SysIsValidArrayIdx(Slot, S3D_DRV_D3D9_MAX_ATTR_CNT)) { if(BankContent.m_TypeDesc != 0) { TexTypeDescArray[TexSlotCnt] = BankContent.m_TypeDesc; TexAttrArray[TexSlotCnt] = Attr; TexSlotArray[TexSlotCnt] = Slot; TexSlotCnt++; VertBufFmtDecl |= s3d_CDrvD3d9VertBufDesc::Decl_Generic; } } break; } case s3d_CDrvGfxEng::AttrChan_Point: { if(Slot == 0) { VertBufFmtDecl |= s3d_CDrvD3d9VertBufDesc::Decl_Point; PointAttr = Attr; } break; } case s3d_CDrvGfxEng::AttrChan_ColorAlpha: { if(Slot == 0) { VertBufFmtDecl |= s3d_CDrvD3d9VertBufDesc::Decl_ColorAlpha; ColorAlphaAttr = Attr; } break; } case s3d_CDrvGfxEng::AttrChan_Normal: { if(Slot == 0) { VertBufFmtDecl |= s3d_CDrvD3d9VertBufDesc::Decl_Normal; NormalAttr = Attr; } break; } case s3d_CDrvGfxEng::AttrChan_BoneWgh: { if(Slot == 0) { VertBufFmtDecl |= s3d_CDrvD3d9VertBufDesc::Decl_BoneWgh; BoneWghAttr = Attr; } break; } case s3d_CDrvGfxEng::AttrChan_BoneSubscr: { if(Slot == 0) { VertBufFmtDecl |= s3d_CDrvD3d9VertBufDesc::Decl_BoneSubscr; BoneSubscrAttr = Attr; } break; } } } // Put dummy data into same vertexbuffer. if(NoDummyBoneVertexBuf) { int DummyAttrCnt = 0; if(!BoneWghAttr && (VertProgUsage & s3d_CDrvD3d9Prog::Usage_BoneWgh)) { VertBufFmtDecl |= s3d_CDrvD3d9VertBufDesc::Decl_DummyBoneWgh; DummyAttrCnt++; } if(!BoneSubscrAttr && (VertProgUsage & s3d_CDrvD3d9Prog::Usage_BoneSubscr)) { VertBufFmtDecl |= s3d_CDrvD3d9VertBufDesc::Decl_DummyBoneSubscr; DummyAttrCnt++; } } D3DVERTEXELEMENT9 *VertElemArray = VertBufDesc.m_VertElemArray; WORD DeclOffs = 0; WORD VertElemStream = 0; if(VertBufFmtDecl & s3d_CDrvD3d9VertBufDesc::Decl_Point) { const D3DVERTEXELEMENT9 DeclPoint = { VertElemStream, DeclOffs, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }; DeclOffs = DeclOffs + S3D_SYS_SIZEOFS(float) * 3; VertBufDesc.m_PointAttr = PointAttr; *VertElemArray++ = DeclPoint; } if(VertBufFmtDecl & s3d_CDrvD3d9VertBufDesc::Decl_BoneWgh || VertBufFmtDecl & s3d_CDrvD3d9VertBufDesc::Decl_DummyBoneWgh) { int Type = D3DDECLTYPE_FLOAT4; if(VertComprFmt && VertComprFmt->m_BoneWgh > 0) Type = VertComprFmt->m_BoneWgh; const D3DVERTEXELEMENT9 DeclBlendWgh = { VertElemStream, DeclOffs, Type, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0 }; DeclOffs = DeclOffs + s3d_CDrvD3d9Util::SizeOfDeclType(Type); VertBufDesc.m_BoneWghAttr = BoneWghAttr; *VertElemArray++ = DeclBlendWgh; } if(VertBufFmtDecl & s3d_CDrvD3d9VertBufDesc::Decl_BoneSubscr || VertBufFmtDecl & s3d_CDrvD3d9VertBufDesc::Decl_DummyBoneSubscr) { const D3DVERTEXELEMENT9 DeclBlendIdx = { VertElemStream, DeclOffs, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0 }; DeclOffs = DeclOffs + S3D_SYS_SIZEOFS(DWORD); VertBufDesc.m_BoneSubscrAttr = BoneSubscrAttr; *VertElemArray++ = DeclBlendIdx; } if(VertBufFmtDecl & s3d_CDrvD3d9VertBufDesc::Decl_ColorAlpha) { const D3DVERTEXELEMENT9 DeclColor = { VertElemStream, DeclOffs, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }; DeclOffs = DeclOffs + S3D_SYS_SIZEOFS(DWORD); VertBufDesc.m_ColorAlphaAttr = ColorAlphaAttr; *VertElemArray++ = DeclColor; } if(VertBufFmtDecl & s3d_CDrvD3d9VertBufDesc::Decl_Normal) { int Type = D3DDECLTYPE_FLOAT3; if(VertComprFmt && VertComprFmt->m_Normal > 0) Type = VertComprFmt->m_Normal; const D3DVERTEXELEMENT9 DeclNormal = { VertElemStream, DeclOffs, Type, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }; DeclOffs = DeclOffs + s3d_CDrvD3d9Util::SizeOfDeclType(Type); VertBufDesc.m_NormalAttr = NormalAttr; *VertElemArray++ = DeclNormal; } for(iTex = 0; iTex < TexSlotCnt; iTex++) { WORD TexOffs = S3D_SYS_SIZEOFS(float) * 2; BYTE TexType = D3DDECLTYPE_FLOAT2; D3DVERTEXELEMENT9 DeclTex; const s3d_CDrvDataTypeDesc *TexTypeDesc = TexTypeDescArray[iTex]; if(TexTypeDesc == s3d_DrvDataGetTypeDesc()) { TexType = D3DDECLTYPE_FLOAT2; TexOffs = S3D_SYS_SIZEOFS(float) * 2; } else if(TexTypeDesc == s3d_DrvDataGetTypeDesc()) { TexOffs = S3D_SYS_SIZEOFS(float); TexType = D3DDECLTYPE_FLOAT1; } else if(TexTypeDesc == s3d_DrvDataGetTypeDesc()) { TexOffs = S3D_SYS_SIZEOFS(float) * 3; TexType = D3DDECLTYPE_FLOAT3; } else if(TexTypeDesc == s3d_DrvDataGetTypeDesc()) { TexOffs = S3D_SYS_SIZEOFS(float) * 4; TexType = D3DDECLTYPE_FLOAT4; } else { S3D_SYS_ASSERT(0); } DeclTex.Stream = VertElemStream; DeclTex.Offset = DeclOffs; DeclTex.Type = TexType; DeclTex.Method = D3DDECLMETHOD_DEFAULT; DeclTex.Usage = D3DDECLUSAGE_TEXCOORD; DeclTex.UsageIndex = TexSlotArray[iTex]; DeclOffs += TexOffs; VertBufDesc.m_TexAttrArray[iTex] = TexAttrArray[iTex]; *VertElemArray++ = DeclTex; } // Put dummy data into extra vertexbuffer. if(!NoDummyBoneVertexBuf) { // those must be last entries! int DummyAttrCnt = 0; if(!BoneWghAttr && (VertProgUsage & s3d_CDrvD3d9Prog::Usage_BoneWgh)) { WORD Stream = S3D_DRV_D3D9_DUMMY_BLENDWGHIDX_STREAM; WORD StreamOffs = 0; const D3DVERTEXELEMENT9 DeclBlendWgh = { Stream, StreamOffs, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0 }; *VertElemArray++ = DeclBlendWgh; DummyAttrCnt++; VertBufFmtDecl |= s3d_CDrvD3d9VertBufDesc::Decl_DummyBoneWgh; } if(!BoneSubscrAttr && (VertProgUsage & s3d_CDrvD3d9Prog::Usage_BoneSubscr)) { WORD Stream = S3D_DRV_D3D9_DUMMY_BLENDWGHIDX_STREAM; WORD StreamOffs = 3 * S3D_SYS_SIZEOFS(DWORD); const D3DVERTEXELEMENT9 DeclBlendIdx = { Stream, StreamOffs, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0 }; *VertElemArray++ = DeclBlendIdx; DummyAttrCnt++; VertBufFmtDecl |= s3d_CDrvD3d9VertBufDesc::Decl_DummyBoneSubscr; } } const D3DVERTEXELEMENT9 DeclEnd = D3DDECL_END(); *VertElemArray++ = DeclEnd; VertBufDesc.m_VertSize = DeclOffs; VertBufDesc.m_VertBufFmtDecl = VertBufFmtDecl; VertBufDesc.m_VertElemCnt = s3d_CSysIntps(VertElemArray - VertBufDesc.m_VertElemArray); } void s3d_CDrvD3d9ProgUtil::ExtractComprFmt( const s3d_CDrvD3d9ProgCtx *ProgCtx, s3d_CUtilStr_cr CodeInfo, s3d_CUtilStr_cr CodeName, s3d_CDrvD3d9Prog *Prog, s3d_CUtilSnkExtract &SnkExtract) { /*@{ @declare{shaderprog.param} {d3d9.hlsl_vertshader.compr_normal}{$ [str]} Use "ubyte4" to enable compression of vertex normals. @}*/ /*@{ @declare{shaderprog.param} {d3d9.asm_vertshader.compr_normal}{$ [str]} See @ident{shaderprog}{d3d9.hlsl_vertshader.compr_normal} @}*/ s3d_CUtilStr TypeStr; s3d_CUtilStr TypeInfo; SnkExtract.ExtractStr(TypeInfo, TypeStr, "compr_normal", false); s3d_CUtilSnkExtractEnum SnkExtractEnum; SnkExtractEnum.Assign(ProgCtx->m_MsgHandler, TypeInfo, TypeStr); int ComprNormal = -1; if(SnkExtractEnum.Check("")) ComprNormal = -1; else if(SnkExtractEnum.Check("ubyte4")) ComprNormal = D3DDECLTYPE_UBYTE4; else SnkExtractEnum.ErrorUnknown(); /*@{ @declare{shaderprog.param} {d3d9.hlsl_vertshader.compr_bonewgh}{$ [str]} Use "ubyte4" to enable compression of bone weights. @}*/ /*@{ @declare{shaderprog.param} {d3d9.asm_vertshader.compr_bonewgh}{$ [str]} See @ident{shaderprog}{d3d9.hlsl_vertshader.compr_bonewgh} @}*/ SnkExtract.ExtractStr(TypeInfo, TypeStr, "compr_bonewgh", false); SnkExtractEnum.Assign(ProgCtx->m_MsgHandler, TypeInfo, TypeStr); int ComprBoneWgh = -1; if(SnkExtractEnum.Check("")) ComprBoneWgh = -1; else if(SnkExtractEnum.Check("ubyte4")) ComprBoneWgh = D3DDECLTYPE_UBYTE4; else SnkExtractEnum.ErrorUnknown(); /* int SampTexArray[S3D_DRV_D3D9_MAX_ATTR_CNT]; s3d_CUtilStrArray TypeStrArray; SnkExtract.ExtractStrArray(TypeStrArray, "compr_attr", false); const s3d_CSysIntps nType = TypeStrArray.GetCnt(); s3d_CSysIntps iType; for(iType = 0; iType < nType; iType++) { SnkExtractEnum.Assign( ProgCtx->m_MsgHandler, TypeInfo, TypeStrArray[iType]); SampTexArray[iType] = -1; if(SnkExtractEnum.Check("")) SampTexArray[iType] = -1; else if(SnkExtractEnum.Check("ubyte4")) SampTexArray[iType] = D3DDECLTYPE_UBYTE4; else if(SnkExtractEnum.Check("short2")) SampTexArray[iType] = D3DDECLTYPE_SHORT2; else SnkExtractEnum.ErrorUnknown(); } */ s3d_CDrvD3d9VertComprFmtPtr VertComprFmt; if(ComprNormal > 0 || ComprBoneWgh > 0)// || nType > 0) { VertComprFmt = S3D_SYS_NEW s3d_CDrvD3d9VertComprFmt; VertComprFmt->m_Normal = ComprNormal; VertComprFmt->m_BoneWgh = ComprBoneWgh; /* s3d_SysMemcpy( VertComprFmt->m_SampTexArray, SampTexArray, S3D_SYS_SIZEOFS(VertComprFmt->m_SampTexArray)); */ } Prog->m_VertComprFmt = VertComprFmt; } bool s3d_CDrvD3d9ProgUtil::CreateCodeBufOfBinData( const s3d_CDrvD3d9ProgCtx *ProgCtx, s3d_CDrvD3d9Buf &CodeBuf, s3d_CSysIntps BinDataLen, const s3d_CSysIntm *BinData) { DWORD ShaderTypeBin = s3d_SysReadInt32uLitEndian(BinData) >> 16; // 0xFFFExxyy d3d vertex shader // 0xFFFFxxyy d3d pixel shader if(ShaderTypeBin == 0xFFFE || ShaderTypeBin == 0xFFFF) { S3D_DRV_D3D9_CHECK( ProgCtx->m_Env, D3DXCreateBuffer( DWORD(BinDataLen), &CodeBuf.EmptyRef())); if(CodeBuf) { void *Dest = CodeBuf->GetBufferPointer(); s3d_SysMemcpy(Dest, BinData, BinDataLen); return true; } } return false; } ///////////////////////////////////////////////////////////////////////////////