/////////////////////////////////////////////////////////////////////////////// // // ## ###### // ###### ### // ## ############### Shark 3D Engine (www.shark3d.com) // ########## # # # // ######## Copyright (c) 1996-2006 Spinor GmbH. // ######### # # # All rights reserved. // ## ########## // ## // /////////////////////////////////////////////////////////////////////////////// //@cpp #include "drv_d3d9_progmgr.h" #include "drv_d3d9_util.h" #include "drv_d3d9_progasm.h" #include "drv_d3d9_proghlsl.h" #include "drv/util/drv_util_gfxunivprog.h" #include "util/snk/util_snk_accesstree.h" /////////////////////////////////////////////////////////////////////////////// s3d_CDrvD3d9ProgMgr::s3d_CDrvD3d9ProgMgr( s3d_CDrvD3d9ProgCtx *ProgCtx) { m_ProgCtx = ProgCtx; m_ValidateProgBuf = false; if(ProgCtx && ProgCtx->m_D3dParam) m_ValidateProgBuf = m_ProgCtx->m_D3dParam->m_ValidateProgBuf; } s3d_CDrvGfxProgPtr s3d_CDrvD3d9ProgMgr::CreateProg( s3d_CUtilNotifGather *NotifGather, s3d_CUtilSnkChunk *Desc) { if(!m_ProgCtx) return 0; s3d_CUtilMsgHandler *MsgHandler = m_ProgCtx->m_MsgHandler; const s3d_CDrvD3d9Param *D3dParam = m_ProgCtx->m_D3dParam; s3d_CUtilStr Info = s3d_CUtilSnkChunk::GetInfoOf(Desc); /*@{ @declare{shaderprog.type}{d3d9}{$ [chunk]} See @ref{prog_ref.shaderprog_type} for other types. @}*/ s3d_CUtilSnkFieldPtr Field = s3d_CUtilSnkAccessTree::AccessFieldVal( MsgHandler, Info, Desc, "d3d9", false, false); s3d_CUtilSnkChunkPtr ParamD3d9 = s3d_CUtilSnkAccess::GetChunk(MsgHandler, Field); if(!ParamD3d9) return 0; s3d_CUtilSnkExtract SnkExtract; SnkExtract.Assign(MsgHandler, ParamD3d9); /*@{ @declare{shaderprog.param}{d3d9.hlsl_vertshader}{$ [chunk]} Parameter chunk for HLSL vertex shader. See @ident{shaderprog}{}. @}*/ s3d_CUtilStr ParamHLSLVertInfo; s3d_CUtilSnkChunkPtr ParamHLSLVert; SnkExtract.ExtractChunk( ParamHLSLVertInfo, ParamHLSLVert, "hlsl_vertshader", false); /*@{ @declare{shaderprog.param}{d3d9.hlsl_pixshader}{$ [chunk]} Parameter chunk for HLSL pixel shader. See @ident{shaderprog}{}. @}*/ s3d_CUtilStr ParamHLSLPixInfo; s3d_CUtilSnkChunkPtr ParamHLSLPix; SnkExtract.ExtractChunk( ParamHLSLPixInfo, ParamHLSLPix, "hlsl_pixshader", false); /*@{ @declare{shaderprog.param}{d3d9.asm_vertshader}{$ [chunk]} Parameter chunk for assembler vertex shader. See @ident{shaderprog}{}. @}*/ s3d_CUtilStr ParamAsmVertInfo; s3d_CUtilSnkChunkPtr ParamAsmVert; SnkExtract.ExtractChunk( ParamAsmVertInfo, ParamAsmVert, "asm_vertshader", false); /*@{ @declare{shaderprog.param}{d3d9.asm_pixshader}{$ [chunk]} Parameter chunk for assembler pixel shader. See @ident{shaderprog}{}. @}*/ s3d_CUtilStr ParamAsmPixInfo; s3d_CUtilSnkChunkPtr ParamAsmPix; SnkExtract.ExtractChunk( ParamAsmPixInfo, ParamAsmPix, "asm_pixshader", false); /*@{ @declare{shaderprog.param}{d3d9.univprog}{$ [chunk]} Parameter chunk for universal program. See @ident{cpp}{s3d_CDrvUtilGfxUnivProg}. @}*/ s3d_CUtilStr ParamUnivProgInfo; s3d_CUtilSnkChunkPtr ParamUnivProg; SnkExtract.ExtractChunk( ParamUnivProgInfo, ParamUnivProg, "univprog", false); SnkExtract.CheckForUnknown(); s3d_CDrvD3d9ProgPtr Prog; if(ParamAsmVert || ParamAsmPix) { Prog = S3D_SYS_NEW s3d_CDrvD3d9ProgAsm( NotifGather, Info, m_ProgCtx, ParamAsmVert, ParamAsmPix); } else if(ParamHLSLVert || ParamHLSLPix) { Prog = S3D_SYS_NEW s3d_CDrvD3d9ProgHLSL( NotifGather, Info, m_ProgCtx, ParamHLSLVert, ParamHLSLPix); } if(Prog && !Prog->IsValid()) { s3d_CUtilMsg m; m.m_Code = "drv/imp/directx/d3d9/drv_d3d9_prog.using_nothing"; m.m_StdTempl = "D3D: Using no vertex/fragment program object"; m.AddInfo(Info); s3d_UtilMsgReportNote(MsgHandler, m); return 0; } s3d_CDrvGfxUnivProgPtr UnivProg; if(ParamUnivProg) { UnivProg = s3d_CDrvUtilGfxUnivProg::CreateProg( MsgHandler, Info, m_ProgCtx->m_UnivProgSuppl, m_ProgCtx->m_UnivProgGivenSuppl, ParamUnivProg); if(!UnivProg || !UnivProg->IsValid()) return 0; // No asm or hsls prog to hold univprog -> create a new progobj if(!Prog) { Prog = S3D_SYS_NEW s3d_CDrvD3d9Prog; Prog->m_Info = Info; } } if(!Prog) return 0; Prog->m_UnivProg = UnivProg; s3d_CUtilStr ProgInfo = Prog->GetInfo(); s3d_CUtilMsg m; m.m_Code = "drv/imp/directx/d3d9/drv_d3d9_prog.using_prog"; m.m_StdTempl = "D3D: Using this vertex/fragment program object."; m.AddInfo(ProgInfo); s3d_UtilMsgReportNote(MsgHandler, m); if(D3dParam->m_ReportProg) { s3d_CUtilMsg m; m.m_Code = "drv/imp/directx/d3d9/drv_d3d9_prog.report_prog_create"; m.m_StdTempl = "D3D: " "Creating program Addr=[1] '[2]'"; m.AddInfo(""); m.AddInfo(s3d_CUtilStrUtil::StrOfPtr(Prog.Get())); m.AddInfo(s3d_CUtilSnkChunk::GetInfoOf(Desc)); s3d_UtilMsgReportNote(MsgHandler, m); } return Prog.Get(); } void s3d_CDrvD3d9ProgMgr::InvalidateProg() { m_CurProg = 0; } void s3d_CDrvD3d9ProgMgr::SelectProg( const s3d_CSysChar *Info, s3d_CDrvD3d9Prog *Prog, const s3d_CSysChar *BufInfo, const s3d_CSysChar *BufDesc, const s3d_CDrvD3d9VertDecl &VertDecl, s3d_CDrvGfxParam_cr GfxParam, const s3d_CDrvD3d9ParamBlk &ParamBlk, s3d_CDrvD3d9ParamBlkState &ParamBlkState) { if(Prog != m_CurProg) { LPDIRECT3DDEVICE9 D3dDev = m_ProgCtx->m_D3dDev; m_CurProg = Prog; if(Prog) { ParamBlkState.Invalidate(); S3D_DRV_D3D9_CHECK( m_ProgCtx->m_Env, D3dDev->SetVertexShader( Prog->m_VertShader)); S3D_DRV_D3D9_CHECK( m_ProgCtx->m_Env, D3dDev->SetPixelShader( Prog->m_PixShader)); if(m_ValidateProgBuf) CheckVertBufIsCompatible(Prog, BufInfo, BufDesc, VertDecl); } else { S3D_DRV_D3D9_CHECK( m_ProgCtx->m_Env, D3dDev->SetVertexShader(0)); S3D_DRV_D3D9_CHECK( m_ProgCtx->m_Env, D3dDev->SetPixelShader(0)); } } if(Prog) { Prog->TrackParams(GfxParam, ParamBlk, ParamBlkState); ParamBlkState.Done(); } } void s3d_CDrvD3d9ProgMgr::TrackTransfBone( s3d_CSysIntps BoneIdxCnt, const s3d_CSysInt32u *BoneIdxData, s3d_CSysIntps MatBoneCnt, const D3DXMATRIXA16 *MatBoneArray) { if(m_CurProg) m_CurProg->TrackTransfBone( BoneIdxCnt, BoneIdxData, MatBoneCnt, MatBoneArray); } bool s3d_CDrvD3d9ProgMgr::CheckVertBufIsCompatible( const s3d_CDrvGfxProg *Prog, const s3d_CSysChar *BufInfo, const s3d_CSysChar *BufDesc, const s3d_CDrvD3d9VertDecl &VertDecl) { if(!Prog) return true; const s3d_CDrvD3d9Prog *ProgImpl = s3d_UtilRecogCastSilent(Prog); if(!ProgImpl) return true; UINT ElemCnt = 0; S3D_DRV_D3D9_CHECK( m_ProgCtx->m_Env, VertDecl->GetDeclaration(0, &ElemCnt)); if(ElemCnt == 0) return false; s3d_CSysIntps AllocSize = ElemCnt * S3D_SYS_SIZEOFS(D3DVERTEXELEMENT9); D3DVERTEXELEMENT9 *ElemArray = reinterpret_cast(alloca(AllocSize)); S3D_DRV_D3D9_CHECK( m_ProgCtx->m_Env, VertDecl->GetDeclaration(ElemArray, &ElemCnt)); const D3DXSEMANTIC *SemanticArray = ProgImpl->m_VertProgDecl.m_SemanticArray; const s3d_CSysIntps nSemantic = ProgImpl->m_VertProgDecl.m_SemanticsCnt; s3d_CSysIntps iSemantic; for(iSemantic = 0; iSemantic < nSemantic; iSemantic++) { DWORD Usage = SemanticArray->Usage; DWORD UsageIdx = SemanticArray->UsageIndex; bool Valid = false; UINT iElem; for(iElem = 0; iElem < ElemCnt; iElem++) { if(ElemArray[iElem].Usage == Usage && ElemArray[iElem].UsageIndex == UsageIdx) { Valid = true; break; } } if(!Valid) { s3d_CUtilStr CodeInfo, CodeName; ProgImpl->GetVertProgCodeInfoName(CodeInfo, CodeName); ReportVertProgIncompatible( CodeInfo, CodeName, ProgImpl->m_VertProgDecl, BufInfo, BufDesc, ElemCnt, ElemArray); return false; } SemanticArray++; } return true; } /////////////////////////////////////////////////////////////////////////////// void s3d_CDrvD3d9ProgMgr::ReportVertProgIncompatible( s3d_CUtilStr_cr CodeInfo, s3d_CUtilStr_cr CodeName, const s3d_CDrvD3d9ProgDecl &VertProgDecl, const s3d_CSysChar *BufInfo, const s3d_CSysChar *BufDesc, s3d_CSysIntps ElemCnt, const D3DVERTEXELEMENT9 *ElemArray) { s3d_CUtilStr VertBufFmtStr = s3d_CDrvD3d9Util::StrOfVertElemArray(ElemCnt, ElemArray); s3d_CUtilStr VertProgDeclStr = s3d_CDrvD3d9Util::StrOfProgDecl(VertProgDecl); s3d_CDrvD3d9Error e; e.m_Code = "drv/imp/directx/d3d9/drv_d3d9_progmgr.prog_incompatible"; e.m_StdTempl = "D3D vertex shader \"[1]\" " "is incompatible " "with vertex declaration of \"[2]\" of object '[3]': " "Vertex shader format is '[4]'. Vertex declaration is '[5]'."; e.AddInfo(CodeInfo); e.AddInfo(CodeName); e.AddInfo(BufInfo); e.AddInfo(BufDesc); e.AddInfo(VertProgDeclStr); e.AddInfo(VertBufFmtStr); s3d_UtilMsgReportError(m_ProgCtx->m_MsgHandler, e); e.Reset(); e.m_Code = "drv/imp/directx/d3d9/drv_d3d9_progmgr.prog_incompatible_sic"; e.m_StdTempl = "Sic: This vertex declaration of object '[1]' " "is incompatible " "with the D3D vertex shader \"[2]\" of shader \"[3]\": " "Vertex shader format is '[4]'. Vertex declaration is '[5]'."; e.AddInfo(BufInfo); e.AddInfo(BufDesc); e.AddInfo(CodeInfo); e.AddInfo(CodeName); e.AddInfo(VertProgDeclStr); e.AddInfo(VertBufFmtStr); s3d_UtilMsgReportError(m_ProgCtx->m_MsgHandler, e); } ///////////////////////////////////////////////////////////////////////////////