#include "stdafx.h" #include "RCKShaderCG.h" #include "ShaderManagerCG.h" #include "CKGL15RasterizerContext.h" #include "CKGL15Rasterizer.h" #include "ShaderDescriptorCG.h" //------------------------------------------------------------------------------- ShaderConstantStore::ShaderConstantStore() : m_CGProgram(NULL), m_GLProgramID(0) { } //------------------------------------------------------------------------------- void ShaderConstantStore::SetProgram(CGprogram program, const char *programString) { XASSERT(!m_CGProgram); // This method should be called only once ! XASSERT(program); GLuint progID = cgGLGetProgramID(program); XASSERT(progID); // program should have been compiled successfully !!! m_CGProgram = program; m_GLProgramID = progID; } //------------------------------------------------------------------------------- void ShaderConstantStore::EnsureSize(int cstCount) { XASSERT(!UsesNamedConstant()); XASSERT(cstCount >= 0); XASSERT(m_ModifiedConstant.Size() == 0); // Not intended to be resized on the fly ... bool hasNamedConstant = false; for (int k = 0; k < m_ConstantArray.Size(); ++k) { if (m_ConstantArray[k].m_Name.Length() != 0) { hasNamedConstant = true; } } if (cstCount > m_ConstantArray.Size()) { XASSERT(!hasNamedConstant); m_ConstantArray.Resize(cstCount); } for (int k = 0; k < cstCount; ++k) { m_ConstantArray[k].m_Index = k; //m_ConstantArray[k].m_Name = "???"; } } //------------------------------------------------------------------------------- int ShaderConstantStore::AddNamedConstant(const char *name) { XASSERT(UsesNamedConstant()); XASSERT(name); XASSERT(strlen(name) > 0); CShaderConstantState cst; cst.m_Name = name; cst.m_Index = m_ConstantArray.Size() - 1; m_ConstantArray.PushBack(cst); return m_ConstantArray.Size() - 1; } //------------------------------------------------------------------------------- void ShaderConstantStore::SetConstant(int index, const float value[4]) { XASSERT(m_ModifiedConstant.Size() <= m_ConstantArray.Size()); XASSERT(index >= 0 && index < m_ConstantArray.Size()); float *destValue = &m_ConstantArray[index].m_Value[0]; // TODO : no cache here !! // To have a working cache; should do the following : // 1 - use cgGLBindProgram, then get initial values // 2 - ensure that cache is invalidated when there's a technique change (some techniques may rely on cgSetParameter to set their constant // because of a profile we don't have a ShaderConstantStore implementation for ...) /* if (destValue[0] == value[0] && destValue[1] == value[1] && destValue[2] == value[2] && destValue[3] == value[3] ) { return; } */ destValue[0] = value[0]; destValue[1] = value[1]; destValue[2] = value[2]; destValue[3] = value[3]; if (!m_ConstantArray[index].m_Modified) { m_ModifiedConstant.PushBack(index); m_ConstantArray[index].m_Modified = true; } else { XASSERT(m_ModifiedConstant.Size() > 0); } XASSERT(m_ModifiedConstant.Size() <= m_ConstantArray.Size()); } //------------------------------------------------------------------------------- void ShaderConstantStore::Flush(CKRasterizerContext *rc) { GLCHECK(); XASSERT(m_ModifiedConstant.Size() <= m_ConstantArray.Size()); if (AreParametersLocal()) { // flush modified parameters only int modifiedConstantCount = m_ModifiedConstant.Size(); for (int ctIndex = 0; ctIndex < modifiedConstantCount; ++ctIndex) { int modifiedConstantIndex = m_ModifiedConstant[ctIndex]; SetConstantInternal(rc, m_ConstantArray[modifiedConstantIndex]); m_ConstantArray[modifiedConstantIndex].m_Modified = false; } } else { // parameters are global -> must set them all // TODO : use EXT_gpu_program_parameters to set several constant at once // and/or use a cache per profile int constantCount = m_ConstantArray.Size(); for (int ctIndex = 0; ctIndex < constantCount; ++ctIndex) { SetConstantInternal(rc, m_ConstantArray[ctIndex]); m_ConstantArray[ctIndex].m_Modified = false; } } m_ModifiedConstant.Resize(0); GLCHECK(); XASSERT(m_ModifiedConstant.Size() <= m_ConstantArray.Size()); } //////////// // ARBVP1 // //////////// //------------------------------------------------------------------------------- void ShaderConstantStoreARBVP1::SetConstantInternal(CKRasterizerContext *rc, CShaderConstantState &cstState) { GLCHECK(); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glProgramLocalParameter4fvARB); ogRC->m_glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, cstState.m_Index, cstState.m_Value); GLCHECK(); } //------------------------------------------------------------------------------- void ShaderConstantStoreARBVP1::BindProgramIntoGL(CKRasterizerContext *rc) { XASSERT(m_GLProgramID); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glBindProgramARB); ogRC->m_glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_GLProgramID); } //////////// // ARBFP1 // //////////// //------------------------------------------------------------------------------- void ShaderConstantStoreARBFP1::SetConstantInternal(CKRasterizerContext *rc, CShaderConstantState &cstState) { GLCHECK(); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glProgramLocalParameter4fvARB); ogRC->m_glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, cstState.m_Index, cstState.m_Value); GLCHECK(); } //------------------------------------------------------------------------------- void ShaderConstantStoreARBFP1::BindProgramIntoGL(CKRasterizerContext *rc) { XASSERT(m_GLProgramID); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glBindProgramARB); ogRC->m_glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_GLProgramID); } ///////////////// // NV programs // ///////////////// //------------------------------------------------------------------------------- void ShaderConstantStoreNVVertex::SetProgram(CGprogram cgProgram, const char *programString) { ShaderConstantStore::SetProgram(cgProgram, programString); const char *currConst = programString; while (currConst) { currConst = strstr(currConst, "#const"); if (!currConst) break; float value[] = { 0.f, 0.f, 0.f, 0.f }; int constantIndex; if (sscanf(currConst, "#const c[%u] = %f %f %f %f", &constantIndex, &value[0], &value[1], &value[2], &value[3] ) >= 2) { EnsureSize(constantIndex + 1); for (int c = 0; c < 4; ++c) m_ConstantArray[constantIndex].m_Value[c] = value[c]; } currConst = strstr(currConst, "\n"); } } //------------------------------------------------------------------------------- void ShaderConstantStoreNVVertex::SetConstantInternal(CKRasterizerContext *rc, CShaderConstantState &cstState) { // NB : constants are global for nv vertex programs // -> must use glProgramParameters4fvNV GLCHECK(); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glProgramParameter4fvNV); if (ogRC->m_glProgramParameter4fvNV) { ogRC->m_glProgramParameter4fvNV(GL_VERTEX_PROGRAM_NV, cstState.m_Index, cstState.m_Value); } GLCHECK(); } //------------------------------------------------------------------------------- void ShaderConstantStoreNVVertex::BindProgramIntoGL(CKRasterizerContext *rc) { GLCHECK(); XASSERT(m_GLProgramID); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glBindProgramNV); if (ogRC->m_glBindProgramNV) { ogRC->m_glBindProgramNV(GL_VERTEX_PROGRAM_NV, m_GLProgramID); } GLCHECK(); } ////////// // FP30 // ////////// //------------------------------------------------------------------------------- void ShaderConstantStoreFP30::SetConstantInternal(CKRasterizerContext *rc, CShaderConstantState &cstState) { // NB : constants are local and named for nv fragment programs (in fact, included directly in shader code) // -> must use glProgramLocalParameter4fvARB GLCHECK(); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glProgramNamedParameter4fvNV); if (ogRC->m_glProgramNamedParameter4fvNV) { XASSERT(cstState.m_Name.Length() != 0); //XASSERT(cstState.m_Name != "???"); ogRC->m_glProgramNamedParameter4fvNV(m_GLProgramID, (GLsizei) cstState.m_Name.Length(), (const GLubyte *) cstState.m_Name.CStr(), cstState.m_Value); } GLCHECK(); } //------------------------------------------------------------------------------- void ShaderConstantStoreFP30::BindProgramIntoGL(CKRasterizerContext *rc) { GLCHECK(); XASSERT(m_GLProgramID); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glBindProgramNV); if (ogRC->m_glBindProgramNV) { ogRC->m_glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, m_GLProgramID); } GLCHECK(); } ////////// // VP40 // ////////// //------------------------------------------------------------------------------- void ShaderConstantStoreVP40::SetConstantInternal(CKRasterizerContext *rc, CShaderConstantState &cstState) { GLCHECK(); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glProgramLocalParameter4fvARB); ogRC->m_glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_NV, cstState.m_Index, cstState.m_Value); GLCHECK(); } //------------------------------------------------------------------------------- void ShaderConstantStoreVP40::BindProgramIntoGL(CKRasterizerContext *rc) { GLCHECK(); XASSERT(m_GLProgramID); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glBindProgramNV); if (ogRC->m_glBindProgramNV) { ogRC->m_glBindProgramNV(GL_VERTEX_PROGRAM_NV, m_GLProgramID); } GLCHECK(); } ////////// // FP40 // ////////// //------------------------------------------------------------------------------- void ShaderConstantStoreFP40::SetConstantInternal(CKRasterizerContext *rc, CShaderConstantState &cstState) { // NB : constants are local and named for nv fragment programs (in fact, included directly in shader code) // -> must use glProgramLocalParameter4fvARB GLCHECK(); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glProgramParameter4fvNV); if (ogRC->m_glProgramLocalParameter4fvARB) { ogRC->m_glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_NV, cstState.m_Index, cstState.m_Value); } GLCHECK(); } //------------------------------------------------------------------------------- void ShaderConstantStoreFP40::BindProgramIntoGL(CKRasterizerContext *rc) { GLCHECK(); XASSERT(m_GLProgramID); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glBindProgramNV); if (ogRC->m_glBindProgramNV) { ogRC->m_glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, m_GLProgramID); } GLCHECK(); } //----------------------------------------------------------------------------- RCKShaderCG::RCKShaderCG(ShaderManagerCG *man) : m_ShaderManager(man), m_CurrTechniqueIndex(-1), m_ShaderText("// Shader") #if defined(MULTIPLESHADERMANAGER) ,m_ShaderName(NULL) #endif ,m_CurrentPassIndex(0) ,m_CurrentPassCount(0) { //--- Initialize the Effect for all render context const int rcCount = man->m_rcList.Size(); m_Effect.Resize(rcCount); m_Effect.Fill(NULL); m_CurrentTechnique.Resize(rcCount); m_CurrentTechnique.Fill(NULL); m_CurrentTechniqueIndex.Resize(rcCount); for (int k = 0; k < rcCount; ++k) { m_EffectStateCachePerContext.PushBack(new EffectStateCache); } m_CurrentTechnique.Fill(0); m_CurrentActivePass.Resize(rcCount); //--- Allocate a ShaderDescriptorCG for each RenderContext m_ShaderDescriptor.Resize(rcCount); for( int rcIndex=0 ; rcIndexGetProtectable(), m_ShaderText); } else return m_ShaderText; } //----------------------------------------------------------------------------- int RCKShaderCG::Begin( CKRenderContext* rc ) { const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc); int NumPasses = 0; if(!m_CurrentTechnique[rcIndex]) { m_CurrentTechnique[rcIndex] = cgGetFirstTechnique(m_Effect[rcIndex]); m_CurrentTechniqueIndex[rcIndex] = 0; } passArray* pPassA = &m_CurrentActivePass[rcIndex]; int pCount = pPassA->Size(); CGpass pass = cgGetFirstPass(m_CurrentTechnique[rcIndex]); while(pass) { if(pCount <= NumPasses) { pPassA->PushBack(pass); ++NumPasses; } else { (*pPassA)[NumPasses] = pass; ++NumPasses; } pass = cgGetNextPass(pass); } m_CurrentPassIndex = 0; m_CurrentPassCount = NumPasses; return NumPasses; } // Defines a bool state that map directly to the state caching system in the rasterizer #define DECLARE_RASTERIZER_STATE(Type, Name, RTState) \ void Name##_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const Type *value, bool reset) \ { \ rc->SetRenderState(RTState, (CKDWORD &) *value); \ } ///////////////// // BOOL STATES // ///////////////// DECLARE_RASTERIZER_STATE(CGbool, DepthMask, VXRENDERSTATE_ZWRITEENABLE) DECLARE_RASTERIZER_STATE(CGbool, ZWriteEnable, VXRENDERSTATE_ZWRITEENABLE) DECLARE_RASTERIZER_STATE(CGbool, LightingEnable, VXRENDERSTATE_LIGHTING) DECLARE_RASTERIZER_STATE(CGbool, LocalViewer, VXRENDERSTATE_LOCALVIEWER) DECLARE_RASTERIZER_STATE(CGbool, Clipping, VXRENDERSTATE_CLIPPING) DECLARE_RASTERIZER_STATE(CGbool, AlphaTestEnable, VXRENDERSTATE_ALPHATESTENABLE) DECLARE_RASTERIZER_STATE(CGbool, BlendEnable, VXRENDERSTATE_ALPHABLENDENABLE) DECLARE_RASTERIZER_STATE(CGbool, DepthTestEnable, VXRENDERSTATE_ZENABLE) DECLARE_RASTERIZER_STATE(CGbool, DitherEnable, VXRENDERSTATE_DITHERENABLE) DECLARE_RASTERIZER_STATE(CGbool, FogEnable, VXRENDERSTATE_FOGENABLE) DECLARE_RASTERIZER_STATE(CGbool, LineSmoothEnable, VXRENDERSTATE_ANTIALIAS) DECLARE_RASTERIZER_STATE(CGbool, NormalizeEnable, VXRENDERSTATE_NORMALIZENORMALS) DECLARE_RASTERIZER_STATE(CGbool, PointSpriteEnable, VXRENDERSTATE_POINTSPRITEENABLE) DECLARE_RASTERIZER_STATE(CGbool, StencilTestEnable, VXRENDERSTATE_STENCILENABLE) // DECLARE_GL_STATE_CALLBACK_BOOL(SpecularEnable, VXRENDERSTATE_SPECULARENABLE) check this one //DECLARE_GL_STATE_CALLBACK_BOOL(LineStipple, VXRENDERSTATE_LINEPATTERN) static void CullFaceEnable_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const CGbool *value, bool reset) { GLCHECK(); if (value[0]) { glEnable(GL_CULL_FACE); } else { glDisable(GL_CULL_FACE); } GLCHECK(); } static void LightEnable_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const CGbool *value, bool reset) { GLCHECK(); (VCKGL15Rasterizer::CKGLRasterizerContext*) rc->EnableLight(cachedState.ArrayIndex, *value); GLCHECK(); } static void ClipPlaneEnable_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const CGbool *value, bool reset) { if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex <= 5) { GLCHECK(); if (*value) { glEnable(GL_CLIP_PLANE0 + cachedState.ArrayIndex); } else { glDisable(GL_CLIP_PLANE0 + cachedState.ArrayIndex); } GLCHECK(); } } static void MultisampleEnable_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const CGbool *value, bool reset) { GLCHECK(); if (*value) { glEnable(GL_MULTISAMPLE); } else { glDisable(GL_MULTISAMPLE); } GLCHECK(); } static void Texture1DEnable_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const CGbool *value, bool reset) { if (reset) return; GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 32) { VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glActiveTextureARB); ogRC->m_glActiveTextureARB(GL_TEXTURE0_ARB + cachedState.ArrayIndex); if (*value) { glEnable(GL_TEXTURE_1D); } else { glDisable(GL_TEXTURE_1D); } } GLCHECK(); } static void Texture2DEnable_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const CGbool *value, bool reset) { if (reset) return; GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 32) { VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glActiveTextureARB); ogRC->m_glActiveTextureARB(GL_TEXTURE0_ARB + cachedState.ArrayIndex); if (*value) { glEnable(GL_TEXTURE_2D); } else { glDisable(GL_TEXTURE_2D); } } GLCHECK(); } static void Texture3DEnable_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const CGbool *value, bool reset) { if (reset) return; GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 32) { VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glActiveTextureARB); ogRC->m_glActiveTextureARB(GL_TEXTURE0_ARB + cachedState.ArrayIndex); if (*value) { glEnable(GL_TEXTURE_3D); } else { glDisable(GL_TEXTURE_3D); } } GLCHECK(); } static void TextureCubeMapEnable_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const CGbool *value, bool reset) { if (reset) return; GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 32) { VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glActiveTextureARB); ogRC->m_glActiveTextureARB(GL_TEXTURE0_ARB + cachedState.ArrayIndex); if (*value) { glEnable(GL_TEXTURE_CUBE_MAP); } else { glDisable(GL_TEXTURE_CUBE_MAP); } } GLCHECK(); } static void TextureRectangleEnable_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const CGbool *value, bool reset) { if (reset) return; GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 32) { VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; XASSERT(ogRC->m_glActiveTextureARB); ogRC->m_glActiveTextureARB(GL_TEXTURE0_ARB + cachedState.ArrayIndex); if (*value) { glEnable(GL_TEXTURE_RECTANGLE_ARB); } else { glDisable(GL_TEXTURE_RECTANGLE_ARB); } } GLCHECK(); } // Registration of states with their default (reset) value static RenderStateDescBool StateDescArrayBool[] = { RenderStateDescBool("CullFaceEnable", CullFaceEnable_CB, true), RenderStateDescBool("ClipPlaneEnable", ClipPlaneEnable_CB, false), RenderStateDescBool("DepthMask", DepthMask_CB, true), RenderStateDescBool("ZWriteEnable", ZWriteEnable_CB, true), RenderStateDescBool("LightEnable", LightEnable_CB, true), RenderStateDescBool("LightingEnable", LightingEnable_CB, true), RenderStateDescBool("LocalViewer", LocalViewer_CB, false), RenderStateDescBool("Clipping", Clipping_CB, true), RenderStateDescBool("AlphaTestEnable", AlphaTestEnable_CB, false), RenderStateDescBool("AlphaBlendEnable", BlendEnable_CB, false), RenderStateDescBool("BlendEnable", BlendEnable_CB, false), RenderStateDescBool("ZEnable", DepthTestEnable_CB, true), RenderStateDescBool("DepthTestEnable", DepthTestEnable_CB, true), RenderStateDescBool("DitherEnable", DitherEnable_CB, false), RenderStateDescBool("FogEnable", FogEnable_CB, false), RenderStateDescBool("LineSmoothEnable", LineSmoothEnable_CB, false), RenderStateDescBool("NormalizeEnable", NormalizeEnable_CB, false), RenderStateDescBool("PointSpriteEnable", PointSpriteEnable_CB, false), RenderStateDescBool("StencilTestEnable", StencilTestEnable_CB, false), RenderStateDescBool("ClipPlaneEnable", ClipPlaneEnable_CB, false), RenderStateDescBool("MultisampleEnable", MultisampleEnable_CB, true), RenderStateDescBool("Texture1DEnable", Texture1DEnable_CB, false), RenderStateDescBool("Texture2DEnable", Texture2DEnable_CB, false), RenderStateDescBool("Texture3DEnable", Texture3DEnable_CB, false), RenderStateDescBool("TextureRectangleEnable", TextureRectangleEnable_CB, false), RenderStateDescBool("TextureCubeMapEnable", TextureRectangleEnable_CB, false), }; //////////////// // INT STATES // //////////////// DECLARE_RASTERIZER_STATE(int, StencilMask, VXRENDERSTATE_STENCILWRITEMASK) // DECLARE_GL_STATE_CALLBACK_INT(DestBlend, VXRENDERSTATE_DESTBLEND) // CONERSION NEEDED !! possibly not always a win since the interface will call glBlendFunc twice ... // DECLARE_GL_STATE_CALLBACK_INT(SrcBlend, VXRENDERSTATE_SRCBLEND) // CONVERSION NEEDED !! possibly not always a win since the interface will call glBlendFunc twice ... // DECLARE_GL_STATE_CALLBACK_INT(DepthFunc, VXRENDERSTATE_ZFUNC) // DECLARE_GL_STATE_CALLBACK_INT(ShadeModel, VXRENDERSTATE_SHADEMODE) // CONVERSION NEEDED !! static void FrontFace_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const int *value, bool reset) { // TODO : use state cache GLCHECK(); CKBOOL ccw = (*value == GL_CCW) ? 1 : 0; VCKGL15Rasterizer::CKGLRasterizerContext* ctx = (VCKGL15Rasterizer::CKGLRasterizerContext*) rc; ccw = ccw ^ ctx->m_InverseWinding ^ ctx->m_TextureTarget; glFrontFace(ccw ? GL_CCW : GL_CW); GLCHECK(); } static void BlendFunc_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const int *value, bool reset) { GLCHECK(); glBlendFunc((GLenum) value[0], (GLenum) value[1]); GLCHECK(); } static void BlendEquation_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const int *value, bool reset) { GLCHECK(); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; if (ogRC->m_glBlendEquation) { ogRC->m_glBlendEquation((GLenum) value[0]); } // NOT SUPPORTED FOR NOW GLCHECK(); } static void FogMode_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const int *value, bool reset) { GLCHECK(); glFogi(GL_FOG_MODE, *value); GLCHECK(); } static void PolygonMode_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const int *value, bool reset) { GLCHECK(); glPolygonMode((GLenum) value[0], (GLenum) value[1]); GLCHECK(); } static void ShadeModel_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const int *value, bool reset) { GLCHECK(); glShadeModel((GLenum) value[0]); GLCHECK(); } static void StencilFunc_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const int *value, bool reset) { GLCHECK(); glStencilFunc((GLenum) value[0], value[1], value[2]); GLCHECK(); } static void StencilOp_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const int *value, bool reset) { GLCHECK(); glStencilOp((GLenum) value[0], (GLenum) value[1], (GLenum) value[2]); GLCHECK(); } // Registration of states static RenderStateDescInt StateDescArrayInt[] = { RenderStateDescInt("StencilMask", StencilMask_CB, 0xffffffff), RenderStateDescInt("FrontFace", FrontFace_CB, GL_CW), RenderStateDescInt("BlendFunc", BlendFunc_CB, GL_ONE, GL_ZERO), RenderStateDescInt("BlendEquation", BlendEquation_CB, GL_FUNC_ADD), RenderStateDescInt("FogMode", FogMode_CB, GL_LINEAR), RenderStateDescInt("PolygonMode", PolygonMode_CB, GL_FRONT_AND_BACK, GL_FILL), RenderStateDescInt("ShadeModel", ShadeModel_CB, GL_SMOOTH), RenderStateDescInt("StencilFunc", StencilFunc_CB, GL_ALWAYS, 0, 0xFFFFFFFF), RenderStateDescInt("StencilOp", StencilOp_CB, GL_KEEP, GL_KEEP, GL_KEEP) }; ////////////////// // FLOAT STATES // ////////////////// DECLARE_RASTERIZER_STATE(float, FogDensity, VXRENDERSTATE_FOGDENSITY) DECLARE_RASTERIZER_STATE(float, FogStart, VXRENDERSTATE_FOGSTART) DECLARE_RASTERIZER_STATE(float, FogEnd, VXRENDERSTATE_FOGEND) DECLARE_RASTERIZER_STATE(float, PointSize, VXRENDERSTATE_POINTSIZE) DECLARE_RASTERIZER_STATE(float, PointSizeMin, VXRENDERSTATE_POINTSIZE_MIN) DECLARE_RASTERIZER_STATE(float, PointSizeMax, VXRENDERSTATE_POINTSIZE_MAX) /*static void AlphaRef_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { rc->SetRenderState(VXRENDERSTATE_ALPHAREF, (CKDWORD) (*value * 255.f)); }*/ // Light callbacks static void LightAmbient_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8) { ((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightFV4(cachedState.ArrayIndex, GL_AMBIENT, value); } GLCHECK(); } static void LightDiffuse_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8) { ((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightFV4(cachedState.ArrayIndex, GL_DIFFUSE, value); } GLCHECK(); } static void LightSpecular_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8) { ((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightFV4(cachedState.ArrayIndex, GL_SPECULAR, value); } GLCHECK(); } static void LightPosition_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8) { ((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightFV4(cachedState.ArrayIndex, GL_POSITION, value); } GLCHECK(); } static void LightSpotDirection_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8) { ((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightFV3(cachedState.ArrayIndex, GL_SPOT_DIRECTION, value); } GLCHECK(); } static void LightSpotExponent_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8) { ((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightF(cachedState.ArrayIndex, GL_SPOT_EXPONENT, *value); } GLCHECK(); } static void LightSpotCutoff_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8) { ((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightF(cachedState.ArrayIndex, GL_SPOT_CUTOFF, *value); } GLCHECK(); } static void LightConstantAttenuation_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8) { ((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightF(cachedState.ArrayIndex, GL_CONSTANT_ATTENUATION, *value); } GLCHECK(); } static void LightLinearAttenuation_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8) { ((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightF(cachedState.ArrayIndex, GL_LINEAR_ATTENUATION, *value); } GLCHECK(); } static void LightQuadraticAttenuation_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); if (cachedState.ArrayIndex >= 0 && cachedState.ArrayIndex < 8) { ((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->GLLightF(cachedState.ArrayIndex, GL_QUADRATIC_ATTENUATION, *value); } GLCHECK(); } // Material callbacks static void MaterialAmbient_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, value); GLCHECK(); } static void MaterialDiffuse_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, value); GLCHECK(); } static void MaterialEmission_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, value); GLCHECK(); } static void MaterialShininess_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, value); GLCHECK(); } static void MaterialSpecular_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, value); GLCHECK(); } // static void FogColor_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); glFogfv(GL_FOG_COLOR, value); GLCHECK(); } static void LightModelAmbient_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, value); GLCHECK(); } static void PointDistanceAttenuation_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); VCKGL15Rasterizer::CKGLRasterizerContext *ogRC = (VCKGL15Rasterizer::CKGLRasterizerContext *) rc; if (ogRC->m_glPointParameterfvARB) { ogRC->m_glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION, value); } GLCHECK(); } static void PolygonOffset_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); glPolygonOffset(value[0], value[1]); GLCHECK(); } static void AlphaFunc_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); glAlphaFunc((GLenum) value[0], value[1]); GLCHECK(); } static void AlphaRef_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const float *value, bool reset) { GLCHECK(); GLint func; glGetIntegerv(GL_ALPHA_TEST_FUNC, &func); glAlphaFunc((GLenum) func, (GLclampf) value[1]); GLCHECK(); } // Registration of states static RenderStateDescFloat StateDescArrayFloat[] = { //RenderStateDescFloat("AlphaRef", AlphaRef_CB, 0.f), RenderStateDescFloat("FogDensity", FogDensity_CB, 1.f), RenderStateDescFloat("FogStart", FogStart_CB, 0.f), RenderStateDescFloat("FogEnd", FogEnd_CB, 1.f), RenderStateDescFloat("PointSize", PointSize_CB, 1.f), RenderStateDescFloat("PointSizeMin", PointSizeMin_CB, 1.f), RenderStateDescFloat("PointSizeMax", PointSizeMax_CB, 64.f), // RenderStateDescFloat("LightAmbient", LightAmbient_CB, 0.f, 0.f, 0.f, 0.f), RenderStateDescFloat("LightDiffuse", LightDiffuse_CB, 0.f, 0.f, 0.f, 0.f), RenderStateDescFloat("LightSpecular", LightSpecular_CB, 0.f, 0.f, 0.f, 0.f), RenderStateDescFloat("LightPosition", LightPosition_CB, 0.f, 0.f, 0.f, 0.f), RenderStateDescFloat("LightConstantAttenuation", LightConstantAttenuation_CB, 0.f), RenderStateDescFloat("LightLinearAttenuation", LightLinearAttenuation_CB, 0.f), RenderStateDescFloat("LightQuadraticAttenuation", LightQuadraticAttenuation_CB, 0.f), RenderStateDescFloat("LightSpotDirection", LightSpotDirection_CB, 0.f, 0.f, 1.f, 0.f), RenderStateDescFloat("LightSpotExponent", LightSpotExponent_CB, 0.f), RenderStateDescFloat("LightSpotCutoff", LightSpotCutoff_CB, 180.f), // RenderStateDescFloat("MaterialAmbient", MaterialAmbient_CB, 0.f, 0.f, 0.f, 0.f), RenderStateDescFloat("MaterialDiffuse", MaterialDiffuse_CB, 0.f, 0.f, 0.f, 0.f), RenderStateDescFloat("MaterialEmissive", MaterialEmission_CB, 0.f, 0.f, 0.f, 0.f), RenderStateDescFloat("MaterialEmission", MaterialEmission_CB, 0.f, 0.f, 0.f, 0.f), RenderStateDescFloat("MaterialShininess", MaterialShininess_CB, 0.f), RenderStateDescFloat("MaterialSpecular", MaterialSpecular_CB, 0.f, 0.f, 0.f, 0.f), // RenderStateDescFloat("FogColor", FogColor_CB, 0.f, 0.f, 0.f, 0.f), // RenderStateDescFloat("LightModelAmbient", LightModelAmbient_CB, 0.f, 0.f, 0.f, 0.f), // RenderStateDescFloat("PointDistanceAttenuation", PointDistanceAttenuation_CB, 1.f, 0.f, 0.f), // RenderStateDescFloat("PolygonOffset", PolygonOffset_CB, 0.f, 0.f), // RenderStateDescFloat("AlphaFunc", AlphaFunc_CB, GL_ALWAYS, 0.f), RenderStateDescFloat("AlphaRef", AlphaRef_CB, 0.f), }; //////////////////// // PROGRAM STATES // //////////////////// //---------------------------------------------------------------------------------------- static void CGProgram_CB(CKRasterizerContext *rc, CachedRenderState &cachedState, const CGprogram *value, bool reset) { GLCHECK(); CGprogram prog = *value; if (!prog) return; if (!reset) { if (cachedState.m_ShaderConstantStore) { // Bind and flush constants on our own instead of using CG cachedState.ShaderManager->EnableProgram(rc, cachedState.m_ShaderConstantStore); } else { cachedState.ShaderManager->EnableProgram(prog); } } // else no op ... programs will be disabled during a call to EndShaders or when switching shaders GLCHECK(); } //---------------------------------------------------------------------------------------- // Registration of states static RenderStateDescProgram StateDescArrayProgram[] = { RenderStateDescProgram("VertexProgram", CGProgram_CB, NULL), RenderStateDescProgram("VertexShader", CGProgram_CB, NULL), RenderStateDescProgram("FragmentProgram", CGProgram_CB, NULL), RenderStateDescProgram("PixelShader", CGProgram_CB, NULL) }; //----------------------------------------------------------------------------- // utility function : build state callback from a state assignement template bool BuildStateAssignmentCache(ShaderManagerCG *shaderManager, CGstateassignment sa, T &cachedState, RenderStateDesc stateDescArray[], int stateDescArraySize ) { XASSERT(shaderManager); CGstate state = cgGetStateAssignmentState(sa); const char *stateName = cgGetStateName(state); // //OutputDebugString(stateName); /*if (strcmp(stateName, "ForceCGSetPassState") == 0) { // special pass to force an eval by cg return false; }*/ // for (int cbIndex = 0; cbIndex < stateDescArraySize; ++cbIndex) { if (strcmp(stateDescArray[cbIndex].m_StateName, stateName) == 0) { cachedState.ShaderManager = shaderManager; cachedState.Callback = stateDescArray[cbIndex].m_Callback; XASSERT(sizeofarray(cachedState.DefaultValue) == sizeofarray(stateDescArray[cbIndex].m_DefaultValue)); for (int i = 0; i < sizeofarray(cachedState.DefaultValue); ++i) { cachedState.StaticValue[i] = cachedState.DefaultValue[i] = stateDescArray[cbIndex].m_DefaultValue[i]; } cachedState.StateAssignment = sa; cachedState.ArrayIndex = cgGetStateAssignmentIndex(sa); // cachedState.NeedReeval = true; return true; } } return false; } /* static volatile bool DumpStateAssign = false; //----------------------------------------------------------------------------- template void ReplayStatesByType(CKRasterizerContext *rc, XArray &states, const typename T::Type *(*cgGetSAValues)(CGstateassignment, int *), bool doReset) { GLCHECK(); for (XArray::Iterator it = states.Begin(); it != states.End(); ++it) { T &cachedState = *it; if (doReset) { GLCHECK(); cachedState.Callback(rc, cachedState, cachedState.DefaultValue, true); GLCHECK(); } else { if (!cachedState.NeedReeval) { GLCHECK(); // value is static cachedState.Callback(rc, cachedState, cachedState.StaticValue, false); GLCHECK(); } else { GLCHECK(); // must ask cg to reevaluate value int valueCount; const T::Type *values = cgGetSAValues(cachedState.StateAssignment, &valueCount); if (numVals <= sizeofarray(cachedState.StaticValue)) { for (int i = 0; i < numVals; ++i) { cachedState.StaticValue[i] = values[i]; } cachedState.UseStaticValue = true; } cachedState.Callback(rc, cachedState, values, false); GLCHECK(); } } } GLCHECK(); } */ static void DumpStates(CKRasterizerContext *rc) { /* static volatile bool dumpStates = false; if (dumpStates) { struct { char *Name; int Value; } stateNames[] = { {"VXRENDERSTATE_ANTIALIAS ", 2}, {"VXRENDERSTATE_TEXTUREPERSPECTIVE ", 4}, //Enable Perspective correction (TRUE/FALSE) {"VXRENDERSTATE_ZENABLE ", 7}, //Enable z test (TRUE/FALSE) {"VXRENDERSTATE_FILLMODE ", 8}, //Fill mode (VXFILL_MODE) {"VXRENDERSTATE_SHADEMODE ", 9}, //Shade mode (VXSHADE_MODE) {"VXRENDERSTATE_LINEPATTERN ", 10}, //Line pattern (bit pattern in a DWORD) {"VXRENDERSTATE_ZWRITEENABLE ", 14}, //Enable z writes (TRUE/FALSE) {"VXRENDERSTATE_ALPHATESTENABLE ", 15}, //Enable alpha tests (TRUE/FALSE) {"VXRENDERSTATE_SRCBLEND ", 19}, //Blend factor for source (VXBLEND_MODE) {"VXRENDERSTATE_DESTBLEND ", 20}, //Blend factor for destination (VXBLEND_MODE) {"VXRENDERSTATE_CULLMODE ", 22}, //Back-face culling mode (VXCULL) {"VXRENDERSTATE_ZFUNC ", 23}, //Z-comparison function (VXCMPFUNC) {"VXRENDERSTATE_ALPHAREF ", 24}, //Reference alpha value (DWORD (0..255) ) {"VXRENDERSTATE_ALPHAFUNC ", 25}, //Alpha-comparison function (VXCMPFUNC) {"VXRENDERSTATE_DITHERENABLE ", 26}, //Enable dithering (TRUE/FALSE) {"VXRENDERSTATE_ALPHABLENDENABLE ", 27}, //Enable alpha blending (TRUE/FALSE) {"VXRENDERSTATE_FOGENABLE ", 28}, //Enable fog (TRUE/FALSE) {"VXRENDERSTATE_SPECULARENABLE ", 29}, //Enable specular highlights (TRUE/FALSE) {"VXRENDERSTATE_FOGCOLOR ", 34}, //Fog color (DWORD ARGB) {"VXRENDERSTATE_FOGPIXELMODE ", 35}, //Fog mode for per pixel fog (VXFOG_MODE) {"VXRENDERSTATE_FOGSTART ", 36}, //Fog start (for both vertex and pixel fog) {"VXRENDERSTATE_FOGEND ", 37}, //Fog end (for both vertex and pixel fog) {"VXRENDERSTATE_FOGDENSITY ", 38}, //Fog density (for both vertex and pixel fog) {"VXRENDERSTATE_EDGEANTIALIAS ", 40}, //Antialias edges (TRUE/FALSE) {"VXRENDERSTATE_ZBIAS ", 47}, //Z-bias (DWORD 0..16) {"VXRENDERSTATE_RANGEFOGENABLE ", 48}, //Enables range-based fog {"VXRENDERSTATE_STENCILENABLE ", 52}, //Enable or disable stenciling (TRUE/FALSE) {"VXRENDERSTATE_STENCILFAIL ", 53}, //Stencil operation (VXSTENCILOP) {"VXRENDERSTATE_STENCILZFAIL ", 54}, //Stencil operation (VXSTENCILOP) {"VXRENDERSTATE_STENCILPASS ", 55}, //Stencil operation (VXSTENCILOP) {"VXRENDERSTATE_STENCILFUNC ", 56}, //Stencil comparison function (VXCMPFUNC) {"VXRENDERSTATE_STENCILREF ", 57}, //Reference value for stencil test (DWORD (0..255)) {"VXRENDERSTATE_STENCILMASK ", 58}, //Mask value used in stencil test (DWORD (0..255)) {"VXRENDERSTATE_STENCILWRITEMASK ", 59}, //Stencil buffer write mask {"VXRENDERSTATE_TEXTUREFACTOR ", 60}, //Texture factor {"VXRENDERSTATE_WRAP0 ", 128}, // Wrap flags for 1st texture coord set (VXWRAP_MODE) {"VXRENDERSTATE_WRAP1 ", 129}, // Wrap flags for 2nd texture coord set (VXWRAP_MODE) {"VXRENDERSTATE_WRAP2 ", 130}, // Wrap flags for 3rd texture coord set (VXWRAP_MODE) {"VXRENDERSTATE_WRAP3 ", 131}, // Wrap flags for 4th texture coord set (VXWRAP_MODE) {"VXRENDERSTATE_WRAP4 ", 132}, // Wrap flags for 5th texture coord set (VXWRAP_MODE) {"VXRENDERSTATE_WRAP5 ", 133}, // Wrap flags for 6th texture coord set (VXWRAP_MODE) {"VXRENDERSTATE_WRAP6 ", 134}, // Wrap flags for 7th texture coord set (VXWRAP_MODE) {"VXRENDERSTATE_WRAP7 ", 135}, // Wrap flags for last texture coord set {"VXRENDERSTATE_CLIPPING ", 136}, //Enable or disable primitive clipping (TRUE/FALSE) {"VXRENDERSTATE_LIGHTING ", 137}, //Enable or disable lighting (TRUE/FALSE) {"VXRENDERSTATE_AMBIENT ", 139}, //Ambient color for scene (DWORD ARGB) {"VXRENDERSTATE_FOGVERTEXMODE ", 140}, //Fog mode for per vertex fog (VXFOG_MODE) {"VXRENDERSTATE_COLORVERTEX ", 141}, //Enable or disable per-vertex color {"VXRENDERSTATE_LOCALVIEWER ", 142}, //Camera relative specular highlights (TRUE/FALSE) {"VXRENDERSTATE_NORMALIZENORMALS ", 143}, //Enable automatic normalization of vertex normals {"VXRENDERSTATE_DIFFUSEFROMVERTEX ", 145}, //If VXRENDERSTATE_COLORVERTEX is TRUE this flags indicate whether diffuse color is taken from the vertex color (TRUE) or from the currently set material (FALSE) {"VXRENDERSTATE_SPECULARFROMVERTEX ", 146}, //If VXRENDERSTATE_COLORVERTEX is TRUE this flags indicate whether specular color is taken from the vertex color (2) or from the currently set material (0) {"VXRENDERSTATE_AMBIENTFROMVERTEX ", 147}, //If VXRENDERSTATE_COLORVERTEX is TRUE this flags indicate whether ambient color is taken from the vertex color (TRUE) or from the currently set material (FALSE) {"VXRENDERSTATE_EMISSIVEFROMVERTEX ", 148}, //If VXRENDERSTATE_COLORVERTEX is TRUE this flags indicate whether emissive color is taken from the vertex color (TRUE) or from the currently set material (FALSE) {"VXRENDERSTATE_VERTEXBLEND ", 151}, //Enable vertex blending and set the number of matrices to use (VXVERTEXBLENDFLAGS) {"VXRENDERSTATE_SOFTWAREVPROCESSING", 153}, //When using a T&L driver in mixed mode}, for the usage of software processing {"VXRENDERSTATE_POINTSIZE ", 154}, //Size of point when drawing point sprites. This value is in screen space units if VXRENDERSTATE_POINTSCALEENABLE is FALSE; otherwise this value is in world space units. {"VXRENDERSTATE_POINTSIZE_MIN ", 155}, //Specifies the minimum size of point primitives. If below 1 the points drawn will disappear when smaller than a pixel {"VXRENDERSTATE_POINTSIZE_MAX ", 166}, //Specifies the maximum size of point primitives. If below 1 the points drawn will disappear when smaller than a pixel {"VXRENDERSTATE_POINTSPRITEENABLE ", 156}, // {"VXRENDERSTATE_POINTSCALEENABLE ", 157}, //If true the size of point will be attenuated according to distance: //Size , pointSize * sqrt(1/ (a + b*dist + c * dist*dist)) where dist //is the distance from viewpoint to point. {"VXRENDERSTATE_POINTSCALE_A ", 158}, // constant attenuation factor for point size computation (see VXRENDERSTATE_POINTSCALEENABLE) {"VXRENDERSTATE_POINTSCALE_B ", 159}, // linear attenuation factor for point size computation (see VXRENDERSTATE_POINTSCALEENABLE) {"VXRENDERSTATE_POINTSCALE_C ", 160}, // quadratic attenuation factor for point size computation (see VXRENDERSTATE_POINTSCALEENABLE) {"VXRENDERSTATE_CLIPPLANEENABLE ", 152}, //Enable one or more user-defined clipping planes ( DWORD mask of planes) {"VXRENDERSTATE_INDEXVBLENDENABLE ", 167}, //Enable indexed vertex blending (to use with VXRENDERSTATE_VERTEXBLEND) {"VXRENDERSTATE_BLENDOP ", 171}, //Set blending operation VXBLENDOP {"VXRENDERSTATE_LOCKMATERIALSTATES ", 252}, // if Enabled}, subsequent calls to CKRasterizerContext::SetMaterial are ignored {"VXRENDERSTATE_TEXTURETARGET ", 253}, // Hint: context is used to render on a texture {"VXRENDERSTATE_INVERSEWINDING ", 254}, // Invert Cull CW and cull CCW (TRUE/FALSE) }; OutputDebugString("==================================================================\n"); for (int k = 0; k < sizeofarray(stateNames); ++k) { rc->InvalidateStateCache((VXRENDERSTATETYPE) stateNames[k].Value); CKDWORD value; if (rc->GetRenderState((VXRENDERSTATETYPE) stateNames[k].Value, &value)) { char buf[512]; sprintf(buf, "%s = 0x%x\n", stateNames[k].Name, value); OutputDebugString(buf); } } OutputDebugString("==================================================================\n"); } */ } //----------------------------------------------------------------------------- static volatile bool UseStateCache = true; //static volatile bool DumpAssgt = false; //----------------------------------------------------------------------------- void RCKShaderCG::ReplayStates(int rcIndex, CKRasterizerContext *rc, PassStateCache &passStateCache, bool doReset) { GLCHECK(); if (passStateCache.m_CallCGSetPassState || (!UseStateCache)) { if (doReset) { GLCHECK(); cgResetPassState(m_CurrentActivePass[rcIndex][m_CurrentPassIndex]); GLCHECK(); // Mark render states cache as potentially invalid (ideally, should set cg callback to use // the state cache, but if we take this code path we're doomed to be slow anyway ...) for (int k = 0; k < VXRENDERSTATE_MAXSTATE; ++k) { rc->InvalidateStateCache((VXRENDERSTATETYPE) k); } } else { GLCHECK(); // clean the program cache, because we don't catch which programs are setup by the call for (int domain = CG_FIRST_DOMAIN; domain < CG_FIRST_DOMAIN + NUMBER_OF_CG_DOMAIN; ++domain) { m_ShaderManager->DeactivateProgram((CGdomain) domain); } GLCHECK(); //cgGLSetManageTextureParameters(cgGetEffectContext(cgGetTechniqueEffect(cgGetPassTechnique((m_CurrentActivePass[rcIndex][m_CurrentPassIndex])))), CG_FALSE); cgSetPassState(m_CurrentActivePass[rcIndex][m_CurrentPassIndex]); // NB Nico V : // Silently discard any GL error from CG here ... // In some cases (setup of a 3D texture after a 2D texture), the cg runtime fails here ... // (though we deactivated the sampler handling by cg through cgGLSetManageTextureParameters , it seem that is calls the GL texture function // anyway ...) glGetError(); /* GLenum err = glGetError(); if (err != GL_NO_ERROR) { char buf[512]; sprintf(buf, "err = %x", err); OutputDebugString(buf); XASSERT(0); } */ // Light setup may have been modified by the call, signal it ((VCKGL15Rasterizer::CKGLRasterizerContext*) rc)->InvalidateLightSetupCache(); GLCHECK(); } } else { GLCHECK(); for (int domain = 0; domain < NUMBER_OF_CG_DOMAIN; ++domain) { if (!passStateCache.m_ProgramEnabled[domain]) { m_ShaderManager->DeactivateProgram((CGdomain) (domain + CG_FIRST_DOMAIN)); } } for (XClassArray::Iterator it = passStateCache.m_RenderStateCacheArray.Begin(); it != passStateCache.m_RenderStateCacheArray.End(); ++it) { /* if (DumpAssgt) { CGstate state = cgGetStateAssignmentState((*it)->StateAssignment); OutputDebugString(cgGetStateName(state)); OutputDebugString(":"); CGtype type = cgGetStateType(state); CGtype baseType = cgGetTypeBase(type); switch(baseType) { case CG_BOOL: { int valueCount; const CGbool *values = cgGetBoolStateAssignmentValues((*it)->StateAssignment, &valueCount); for (int v = 0; v < valueCount; ++v) { OutputDebugString(values[v] ? "true" : "false"); } } break; case CG_FLOAT: { int valueCount; const float *values = cgGetFloatStateAssignmentValues((*it)->StateAssignment, &valueCount); for (int v = 0; v < valueCount; ++v) { char buf[128]; sprintf(buf, "%f", values[v]); OutputDebugString(buf); } } break; case CG_INT: { int valueCount; const int *values = cgGetIntStateAssignmentValues((*it)->StateAssignment, &valueCount); for (int v = 0; v < valueCount; ++v) { char buf[128]; sprintf(buf, "%d", values[v]); OutputDebugString(buf); } } break; default: break; } OutputDebugString(" "); OutputDebugString("\n"); } */ (*it)->Apply(rc, doReset); } m_ShaderManager->ClearModifiedRenderStates(); // We applied all render state already so, clear the state that were marked as 'dirty' // TODO : better design for this ... //DumpStates(rc); } GLCHECK(); } //----------------------------------------------------------------------------- void RCKShaderCG::PassStateCache::RemoveConstantStores() { for (int domain = 0; domain < NUMBER_OF_CG_DOMAIN; ++domain) { delete m_ConstantStore[domain]; m_ConstantStore[domain] = NULL; m_ProgramEnabled[domain] = false; } for (XArray::Iterator it = m_RenderStateCacheArray.Begin(); it != m_RenderStateCacheArray.End(); ++it) { (*it)->m_ShaderConstantStore = NULL; } } //----------------------------------------------------------------------------- void RCKShaderCG::TechniqueStateCache::RemoveConstantStores() { for (int passIndex = 0; passIndex < m_Passes.Size(); ++passIndex) { m_Passes[passIndex]->RemoveConstantStores(); } } //----------------------------------------------------------------------------- void RCKShaderCG::MarkSamplerStateConnectedParameters(CGeffect effect, ShaderDescriptorCG::ShaderCG *shaderCG) { int techniqueCount = ShaderManagerCG::GetCGEffectTechniqueCount(effect); CGparameter currParam = cgGetFirstEffectParameter(effect); while (currParam) { CGstateassignment sa = cgGetFirstSamplerStateAssignment(currParam); while (sa) { int numConnectedParams = cgGetNumDependentStateAssignmentParameters(sa); for (int paramIndex = 0; paramIndex < numConnectedParams; ++paramIndex) { CGparameter param = cgGetDependentStateAssignmentParameter(sa, paramIndex); ShaderDescriptorCG::ShaderCG::CGParamToMeaningMap::Iterator it = shaderCG->m_CGParamToMeaning.Find(param); if (it != shaderCG->m_CGParamToMeaning.End()) { XASSERT((*it)->m_PerTechniquePerPassConstantSetup.Size() == techniqueCount); // TODO : we could disambiguate sampler per technique here, but never seen it used // anyway, so don't seem worth the trouble ... for (int techIndex = 0; techIndex < techniqueCount; ++techIndex) { ShaderDescriptorCG::ParamMeaning::TechniqueConstantSetupInfo &tech = (*it)->m_PerTechniquePerPassConstantSetup[techIndex]; tech.m_ForceUseCGSetParameter = true; // we *must* call cgSetParameterxxx so that // the dependent sampler states can be recomputed tech.m_HasDependentSamplerStates = true; } } } sa = cgGetNextStateAssignment(sa); } currParam = cgGetNextParameter(currParam); } } //-----------------------------------------------------------------------------f void RCKShaderCG::RecordEffectStates(CGeffect effect, ShaderDescriptorCG::ShaderCG *shaderCG, EffectStateCache &effectStateCache) { XASSERT(!effectStateCache.m_StateCacheRecorded); // MarkSamplerStateConnectedParameters(effect, shaderCG); // update state cache // int techIndex = 0; for (CGtechnique tech = cgGetFirstTechnique(effect); tech; tech = cgGetNextTechnique(tech), ++techIndex) { int passIndex = 0; bool unsupportedProfileFound = false; TechniqueStateCache *tsc = new TechniqueStateCache; for (CGpass pass = cgGetFirstPass(tech); pass; pass = cgGetNextPass(pass), ++passIndex) { const char *compiledPrograms[NUMBER_OF_CG_DOMAIN] = { NULL, NULL, NULL }; bool cstSetupSupportedPerDomain[NUMBER_OF_CG_DOMAIN] = { true, true, true }; // for each domain, true, if we support setup of // constants for that profile PassStateCache *psc = new PassStateCache; for (int domainIndex = 0; domainIndex < NUMBER_OF_CG_DOMAIN; ++domainIndex) { psc->m_ProgramEnabled[domainIndex] = false; } psc->m_CallCGSetPassState = false; psc->m_TextureStageBits = 0; psc->m_LightPositionRenderState = NULL; psc->m_LightSpotDirectionRenderState = NULL; bool fragmentProgramFound = false; // XArray cachedRenderStates; // #ifdef STATIC_FOR_MAYA // Maya export dll links with a cg that don't have // cgGetTypeSizes -> link would fail psc->m_CallCGSetPassState = true; CGstateassignment sa; // dummy XASSERT(0); if (0) #else for (CGstateassignment sa = cgGetFirstStateAssignment(pass); sa; sa = cgGetNextStateAssignment(sa)) #endif { bool found = false; CGstate state = cgGetStateAssignmentState(sa); // CGtype baseType;//cgGetTypeBase(type); int nrows = 0, ncols = 0; #ifndef STATIC_FOR_MAYA CGtype type;//cgGetStateType(state); type = cgGetStateType(state); baseType = cgGetTypeBase(type); cgGetTypeSizes(type, &nrows, &ncols); #else XASSERT(0); // shouldn't go here ... #endif if (nrows <= 1) // 0 for programs ... { switch(baseType) { //---------------------------------------------------------------------- case CG_BOOL: { CachedRenderStateBool *sc = new CachedRenderStateBool; found = BuildStateAssignmentCache(m_ShaderManager, sa, *sc, StateDescArrayBool, sizeofarray(StateDescArrayBool) ); if (found) { psc->m_RenderStateCacheArray.PushBack(sc); cachedRenderStates.PushBack(sc); // If this is texture enabled, mark the corresponding texture stage as 'used' // we don't record the texture assignemnent state, because they // are handled explicitly elsewhere (by ParamMeaning_Sampler) if (sc->Callback == Texture1DEnable_CB || sc->Callback == Texture2DEnable_CB || sc->Callback == Texture3DEnable_CB || sc->Callback == TextureCubeMapEnable_CB || sc->Callback == TextureRectangleEnable_CB ) { psc->m_TextureStageBits |= (1 << cgGetStateAssignmentIndex(sa)); } } else { delete sc; } } break; //---------------------------------------------------------------------- case CG_INT: { CachedRenderStateInt *sc = new CachedRenderStateInt; found = BuildStateAssignmentCache(m_ShaderManager, sa, *sc, StateDescArrayInt, sizeofarray(StateDescArrayInt) ); if (found) { psc->m_RenderStateCacheArray.PushBack(sc); cachedRenderStates.PushBack(sc); } else { delete sc; } } break; //---------------------------------------------------------------------- case CG_FLOAT: { CachedRenderStateFloat *sc = new CachedRenderStateFloat; found = BuildStateAssignmentCache(m_ShaderManager, sa, *sc, StateDescArrayFloat, sizeofarray(StateDescArrayFloat) ); if (found) { psc->m_RenderStateCacheArray.PushBack(sc); cachedRenderStates.PushBack(sc); if (sc->Callback == LightPosition_CB) { psc->m_LightPositionRenderState = sc; } if (sc->Callback == LightSpotDirection_CB) { psc->m_LightSpotDirectionRenderState = sc; } } else { delete sc; } } break; //---------------------------------------------------------------------- case CG_PROGRAM_TYPE: { CGprogram prog = cgGetProgramStateAssignmentValue(sa); if (prog) { GLCHECK(); if (!cgIsProgramCompiled(prog)) { cgCompileProgram(prog); } GLCHECK(); if (!cgGLIsProgramLoaded(prog)) { cgGLLoadProgram(prog); GLCHECK(); cgSetPassProgramParameters(prog); GLCHECK(); } GLCHECK(); const char *compiledProgramString = NULL; #ifndef STATIC_FOR_MAYA GLCHECK(); compiledProgramString = cgGetProgramString(prog, CG_COMPILED_PROGRAM); GLCHECK(); /* OutputDebugString("=============================================\n"); OutputDebugString(compiledProgramString); OutputDebugString("=============================================\n"); */ GLCHECK(); CGprofile profile = cgGetProgramProfile(prog); CGdomain domain = cgGetProfileDomain(profile); switch (domain) { case CG_VERTEX_DOMAIN: compiledPrograms[0] = compiledProgramString; break; case CG_FRAGMENT_DOMAIN: compiledPrograms[1] = compiledProgramString; break; case CG_GEOMETRY_DOMAIN: compiledPrograms[2] = compiledProgramString; break; default: domain = CG_UNKNOWN_DOMAIN; } GLCHECK(); if (domain == CG_UNKNOWN_DOMAIN) { cachedRenderStates.PushBack(NULL); found = true; // null assignment is valid, don't cancel the build of other states break; } #endif CachedRenderStateProgram *sc = new CachedRenderStateProgram; found = BuildStateAssignmentCache(m_ShaderManager, sa, *sc, StateDescArrayProgram, sizeofarray(StateDescArrayProgram) ); XASSERT(found); psc->m_RenderStateCacheArray.PushBack(sc); cachedRenderStates.PushBack(sc); #ifndef STATIC_FOR_MAYA // Maya export dll links with a cg that don't have // cgGetProfileDomain -> link would fail XASSERT(domain < CG_FIRST_DOMAIN + NUMBER_OF_CG_DOMAIN); psc->m_ProgramEnabled[domain - CG_FIRST_DOMAIN] = true; // build constant store for that profile if supported ShaderConstantStore *shCstStore = NULL; if (prog && strlen(compiledProgramString)) //if compilation succesful { switch (profile) { case CG_PROFILE_ARBFP1: shCstStore = new ShaderConstantStoreARBFP1; break; case CG_PROFILE_ARBVP1: shCstStore = new ShaderConstantStoreARBVP1; break; // case CG_PROFILE_FP20: // GeForce3 NV_texture_shader & NV_register_combiners // -> not worth handling yet ... break; case CG_PROFILE_FP30: // not supported yet (constants are represented by name ...) shCstStore = new ShaderConstantStoreFP30; break; case CG_PROFILE_FP40: // not supported yet (constants are represented by name ...) shCstStore = new ShaderConstantStoreFP40; break; // case CG_PROFILE_VP20: shCstStore = new ShaderConstantStoreVP20; break; case CG_PROFILE_VP30: shCstStore = new ShaderConstantStoreVP30; break; case CG_PROFILE_VP40: shCstStore = new ShaderConstantStoreVP40; break; // } } if (shCstStore) { shCstStore->SetProgram(prog, compiledProgramString); } else { cstSetupSupportedPerDomain[domain - CG_FIRST_DOMAIN] = false; unsupportedProfileFound = true; } psc->m_ConstantStore[domain - CG_FIRST_DOMAIN] = shCstStore; sc->m_ShaderConstantStore = shCstStore; // if (cgGetProfileDomain(cgGetProgramProfile(prog)) == CG_FRAGMENT_DOMAIN) { fragmentProgramFound = true; } #endif } else { cachedRenderStates.PushBack(NULL); found = true; // null assignment is valid, don't cancel the build of other states } } break; case CG_SAMPLER1D: case CG_SAMPLER2D: case CG_SAMPLER3D: case CG_SAMPLERRECT: case CG_SAMPLERCUBE: { found = true; psc->m_TextureStageBits |= (1 << cgGetStateAssignmentIndex(sa)); cachedRenderStates.PushBack(NULL); } break; default: break; } } if (!found) { /* OutputDebugString("Unknown state : "); OutputDebugString(cgGetStateName(state)); OutputDebugString("\n"); OutputDebugString(cgGetTypeString(cgGetStateType(state))); OutputDebugString("\n"); */ // Don't know this state ... we can't call CG default callback, so must // do a full cgSetPassState as a callback psc->m_CallCGSetPassState = true; cachedRenderStates.PushBack(NULL); } } if (!fragmentProgramFound) { /* if (this != m_ShaderManager->m_DefaultShader) { // Fallback on cg runtime when no fragment program is found (don't no why, but incorrect // material parameters on first frame else ... most of the time this won't be used, so a fallback is ok) psc.m_CallCGSetPassState = true; } */ } if (psc->m_CallCGSetPassState) { psc->m_LightPositionRenderState = NULL; psc->m_LightSpotDirectionRenderState = NULL; // We don't know all render states ... must fallback to cgSetPassState for that pass psc->ClearRenderStateCache(); psc->RemoveConstantStores(); for (int domain = 0; domain < NUMBER_OF_CG_DOMAIN; ++ domain) { cstSetupSupportedPerDomain[domain] = FALSE; } } #ifndef STATIC_FOR_MAYA { // For each render states, see which parameters are needed to compute them CGpass currPass = cgGetFirstPass(tech); int cachedRenderStateIndex = 0; CGstateassignment sa = cgGetFirstStateAssignment(pass); while (sa) { if (cachedRenderStates[cachedRenderStateIndex]) { int numDependentParameters = cgGetNumDependentStateAssignmentParameters(sa); for (int paramIndex = 0; paramIndex < numDependentParameters; ++paramIndex) { CGparameter param = cgGetDependentStateAssignmentParameter(sa, paramIndex); ShaderDescriptorCG::ShaderCG::CGParamToMeaningMap::Iterator it = shaderCG->m_CGParamToMeaning.Find(param); if (it != shaderCG->m_CGParamToMeaning.End()) { ShaderDescriptorCG::ParamMeaning::TechniqueConstantSetupInfo &tech = (*it)->m_PerTechniquePerPassConstantSetup[techIndex]; /*char buf[512]; sprintf(buf, "%s depends on %s\n", cgGetStateName(cgGetStateAssignmentState(sa)), cgGetParameterName(param)); OutputDebugString(buf);*/ if (!psc->m_CallCGSetPassState) { tech.m_DependentRenderStates.PushBack(cachedRenderStates[cachedRenderStateIndex]); } tech.m_ForceUseCGSetParameter = true; // we *must* call cgSetParameterxxx so that // the dependent render state can be recomputed } } } sa = cgGetNextStateAssignment(sa); ++cachedRenderStateIndex; } XASSERT(cachedRenderStateIndex == cachedRenderStates.Size()); // now, setup the constants setup info for each meaning shaderCG->InitConstantSetupInfo(techIndex, passIndex, compiledPrograms, psc->m_ConstantStore); // Compute the number of constant needed by each program domain for (int domain = 0; domain < NUMBER_OF_CG_DOMAIN; ++ domain) { if (compiledPrograms[domain] && cstSetupSupportedPerDomain[domain] && psc->m_ConstantStore[domain] && !psc->m_ConstantStore[domain]->UsesNamedConstant() ) { XASSERT(psc->m_ConstantStore[domain]); if (!psc->m_ConstantStore[domain]->UsesNamedConstant()) { int constantCount = shaderCG->ComputeMaxParamMeaningCstIndex(techIndex, passIndex, (CGdomain) (domain + CG_FIRST_DOMAIN)) + 1; if (constantCount > 0) { psc->m_ConstantStore[domain]->EnsureSize(constantCount); } } } } } #endif tsc->m_Passes.PushBack(psc); // end of pass } effectStateCache.m_TechniquesStateCache.PushBack(tsc); // for this technique bool invalidateTechniqueConstantWrap = false; if (unsupportedProfileFound) { // Note 1 : Invalidate the whole technique !!! Even if some profile are supported // calling setCGParameter for a parameter may set constant in other pass or domain that we support // (example : mixing fp20 with vp20). However, some supported profiles (e.g those we know how to set constants into) // do not have local constants (e.g vp 20) -> require a call to cgGLBindProgram to bind *all* the constant for real! (so conflict with our constant // store that do the whole setup at the end as well ... we can't mix the 2 -> we must invalidate the whole technique...) // We could have a finer granularity than that, but discard the whole thing for simplicity... invalidateTechniqueConstantWrap = true; } else { // If a parameter has both dependent render states (or sampler states), and set constants in some profile // (very unlikely and do not seem useful, but can be done ...) // then the call to cgSetParameter (we require it since is it needed to eval the new render state value from cg) // may conflict with our constant wrapper (see Note 1 above to see an example where this situation happens) // NB 1 : when we support wrapping for a profile, then *all* constants are wrapped, thus, call to cgSetParameter // only happen when an effect parameter has a dependent render state and set no constants ... for (XArray::Iterator it = shaderCG->GetParamMeanings().Begin(); it != shaderCG->GetParamMeanings().End() && !invalidateTechniqueConstantWrap; ++it) { if ((*it)->HasDependentStates(techIndex)) { if ((*it)->HasDependentProgramConstants(techIndex)) { invalidateTechniqueConstantWrap = true; } } } for (XArray::Iterator it = shaderCG->GetPerPassParamMeanings().Begin(); it != shaderCG->GetPerPassParamMeanings().End() && !invalidateTechniqueConstantWrap; ++it) { if ((*it)->HasDependentStates(techIndex)) { if ((*it)->HasDependentProgramConstants(techIndex)) { invalidateTechniqueConstantWrap = true; } } } for (XArray::Iterator it = shaderCG->GetExposedParamMeanings().Begin(); it != shaderCG->GetExposedParamMeanings().End() && !invalidateTechniqueConstantWrap; ++it) { if ((*it)->HasDependentStates(techIndex)) { if ((*it)->HasDependentProgramConstants(techIndex)) { invalidateTechniqueConstantWrap = true; } } } } if (invalidateTechniqueConstantWrap) { tsc->RemoveConstantStores(); shaderCG->DisableProgramConstantsWrapping(techIndex); } // end of technique } // shaderCG->m_CGParamToMeaning.Clear(); // the hash map was only necessary for the build, get rid of it. // effectStateCache.m_StateCacheRecorded = true; } //----------------------------------------------------------------------------- void RCKShaderCG::BeginPass( CKDWORD Num, CKRenderContext* rc ) { GLCHECK(); const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc); EffectStateCache &efsc = *m_EffectStateCachePerContext[rcIndex]; XASSERT(efsc.m_StateCacheRecorded); /*if (!efsc.m_StateCacheRecorded) { RecordEffectStates(m_Effect[rcIndex], m_ShaderDescriptor[rcIndex], efsc); }*/ m_CurrentPassIndex = Num; int currentTechniqueIndex = m_CurrentTechniqueIndex[rcIndex]; PassStateCache &psc = *(efsc.m_TechniquesStateCache[currentTechniqueIndex]->m_Passes[m_CurrentPassIndex]); ReplayStates(rcIndex, rc->GetRasterizerContext(), psc, false /* doReset */); // if this is a fixed fragment program, then unbound all unused texture stages if (!psc.m_ProgramEnabled[CG_FRAGMENT_DOMAIN]) { m_ShaderManager->DisableTextureStages(rc->GetRasterizerContext(), psc.m_TextureStageBits); } GLCHECK(); } //----------------------------------------------------------------------------- void RCKShaderCG::EndPass( CKRenderContext* rc ) { GLCHECK(); const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc); // EffectStateCache &efsc = *m_EffectStateCachePerContext[rcIndex]; XASSERT(efsc.m_StateCacheRecorded); // int currentTechniqueIndex = m_CurrentTechniqueIndex[rcIndex]; PassStateCache &psc = *(efsc.m_TechniquesStateCache[currentTechniqueIndex]->m_Passes[m_CurrentPassIndex]); ReplayStates(rcIndex, rc->GetRasterizerContext(), psc, true /* doReset */); ++ m_CurrentPassIndex; // Necessary to increase the pass index because some meaning setup // happen before the call to BeginPass, and require the current pass index if (m_CurrentPassIndex == m_CurrentPassCount) { m_CurrentPassIndex = 0; // reset for next shader invocation } m_ShaderManager->ClearModifiedRenderStates(); // for safety GLCHECK(); } //----------------------------------------------------------------------------- void RCKShaderCG::CommitChanges( CKRenderContext* rc ) { const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc); EffectStateCache &efsc = *m_EffectStateCachePerContext[rcIndex]; XASSERT(efsc.m_StateCacheRecorded); // int currentTechniqueIndex = m_CurrentTechniqueIndex[rcIndex]; PassStateCache &psc = *(efsc.m_TechniquesStateCache[currentTechniqueIndex]->m_Passes[m_CurrentPassIndex]); if (psc.m_CallCGSetPassState || (!UseStateCache)) { // fallback when some render state are unknown (should use the optimized path instead of this most of the time) cgSetPassState(m_CurrentActivePass[rcIndex][m_CurrentPassIndex]); } else { m_ShaderManager->FlushModifiedRenderStates(m_CurrentPassIndex, rc->GetRasterizerContext()); // if this is a fixed fragment program, then unbound all unused texture stages if (!psc.m_ProgramEnabled[CG_FRAGMENT_DOMAIN]) { m_ShaderManager->DisableTextureStages(rc->GetRasterizerContext(), psc.m_TextureStageBits); } // flush program constants for (int domain = 0; domain < NUMBER_OF_CG_DOMAIN; ++domain) { if (psc.m_ConstantStore[domain]) { psc.m_ConstantStore[domain]->Flush(rc->GetRasterizerContext()); } } } GLCHECK(); } //----------------------------------------------------------------------------- void RCKShaderCG::End( CKRenderContext* rc ) { GLCHECK(); } //----------------------------------------------------------------------------- void RCKShaderCG::SetTechnique( const XString& iTechName ) { const int rcCount = m_Effect.Size(); for( int rcIndex=0 ; rcIndex fill the technique array at compilation time, whith the shader descriptor") m_CurrTechniqueIndex = iTechIndex; const int rcCount = m_Effect.Size(); for( int rcIndex=0 ; rcIndexGetTechMeanings().Size(); } //----------------------------------------------------------------------------- bool RCKShaderCG::GetTechIndexByName( const XString& iTechName, int& oPos ) const { //--- Tech Name Should be the same for all Render Contexts if( !m_ShaderDescriptor.Size() ) return false; oPos = m_ShaderDescriptor[0]->GetTechIndexByName( iTechName ); if( oPos == -1 ) return false; return true; } //----------------------------------------------------------------------------- void RCKShaderCG::GetTechniqueInfo( int iTechIndex, TechniqueInfo& oTechInfo ) const { if( !m_ShaderDescriptor.Size() ) return; XArray& techMeanings = m_ShaderDescriptor[0]->GetTechMeanings(); ShaderDescriptorCG::TechMeaning& techMeaning = *techMeanings[ iTechIndex ]; oTechInfo.name = XString(cgGetTechniqueName(techMeaning.m_TechDesc)); oTechInfo.desc = techMeaning.m_DescStr; oTechInfo.isValid = techMeaning.m_Validated; } //----------------------------------------------------------------------------- bool RCKShaderCG::FindNextValidTechnique( int& ioTechIndex, XString* oTechName ) const { if( !m_ShaderDescriptor.Size() ) return false; //--- Use Shader Descriptor of Render Context 0 (validation should be the same for all RC) ShaderDescriptorCG::ShaderCG& shaderDescriptor = *m_ShaderDescriptor[0]; //--- Parse all technique from the given one TechniqueInfo techInfo; int techIndex = ioTechIndex; if( techIndex == -1 ) techIndex = 0; const int techCount = GetTechniquesCount(); for( ; techIndexGetDefaultShader() ) return 1; if( !m_ShaderDescriptor.Size() ) return 0; XArray& techMeanings = m_ShaderDescriptor[0]->GetTechMeanings(); ShaderDescriptorCG::TechMeaning& techMeaning = *techMeanings[ iTechIndex ]; return techMeaning.m_Passes.Size(); } //----------------------------------------------------------------------------- void RCKShaderCG::GetPassInfo( int iTechIndex, int iPassIndex, PassInfo& oPassInfo ) const { if( !m_ShaderDescriptor.Size() ) return; //--- Should be the same for RC0 than for other RC XArray& techMeanings = m_ShaderDescriptor[0]->GetTechMeanings(); ShaderDescriptorCG::TechMeaning& techMeaning = *techMeanings[ iTechIndex ]; ShaderDescriptorCG::PassMeaning& passMeaning = *techMeaning.m_Passes[ iPassIndex ]; oPassInfo.name = XString(cgGetPassName(passMeaning.m_PassDesc)); oPassInfo.desc = passMeaning.m_DescStr; } //----------------------------------------------------------------------------- bool RCKShaderCG::GetPassIndexByName( int iTechIndex, const char* iPassName, int& oPos ) const { if( !m_ShaderDescriptor.Size() ) return false; //--- Should be the same for RC0 than for other RC XArray& techMeanings = m_ShaderDescriptor[0]->GetTechMeanings(); ShaderDescriptorCG::TechMeaning& techMeaning = *techMeanings[ iTechIndex ]; //--- Find index of given technique int passIndex = techMeaning.GetPassIndexByName( iPassName ); //--- Cannot find the given pass if( passIndex == -1 ) return false; oPos = passIndex; return true; } //----------------------------------------------------------------------------- // Effect parameters feature //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // Execute Exposed Params Meanings void RCKShaderCG::SetParameters(const XArray& params) { GLCHECK(); CKRenderManager* rm = m_ShaderManager->m_Context->GetRenderManager(); const int rcCount = m_Effect.Size(); for( int rcIndex=0 ; rcIndexm_rcList[rcIndex]; int techIndex = m_CurrentTechniqueIndex[rcIndex]; XASSERT(m_EffectStateCachePerContext[rcIndex]->m_StateCacheRecorded); TechniqueStateCache *tsc = m_EffectStateCachePerContext[rcIndex]->m_TechniquesStateCache[techIndex]; // ShaderDescriptorCG::MeaningProcessingInfo MPI( NULL, NULL, m_Effect[rcIndex], rc, NULL, m_ShaderDescriptor[rcIndex], NULL, m_CurrentTechniqueIndex[rcIndex], false /* per pass meaning */, tsc); for (int i = 0; i < params.Size(); ++i) { GLCHECK(); CKParameterLocal* param = params[i]; ShaderDescriptorCG::ExposedParamMeaning* exposedParamMeaning = m_ShaderManager->_GetRegisteredParamMeaning( param, rcIndex ); if( !exposedParamMeaning ) continue; MPI.param = param; exposedParamMeaning->ProcessCallBack( MPI ); GLCHECK(); } } GLCHECK(); } //----------------------------------------------------------------------------- // Execute Params Meanings (non-exposed) // called by SetValuesOfUsedAutomatics() // void RCKShaderCG::ExecuteMeanings( CK3dEntity* iEnt, CKMaterial* iMat, CKMaterialShader* iMatShader, CKRenderContext* iRC ) { const int rcIndex = m_ShaderManager->_GetRenderContextIndex( iRC ); int techIndex = m_CurrentTechniqueIndex[rcIndex]; XASSERT(m_EffectStateCachePerContext[rcIndex]->m_StateCacheRecorded); TechniqueStateCache *tsc = m_EffectStateCachePerContext[rcIndex]->m_TechniquesStateCache[techIndex]; ShaderDescriptorCG::MeaningProcessingInfo mpi( iEnt, iMat, m_Effect[rcIndex], iRC, iMatShader, m_ShaderDescriptor[rcIndex], NULL, techIndex, false /* per pass meaning */, tsc); m_ShaderDescriptor[rcIndex]->ExecuteMeanings( mpi ); int currentTechniqueIndex = m_CurrentTechniqueIndex[rcIndex]; EffectStateCache &efsc = *m_EffectStateCachePerContext[rcIndex]; if (efsc.m_TechniquesStateCache.Size() != 0) { XClassArray& passes = efsc.m_TechniquesStateCache[currentTechniqueIndex]->m_Passes; if (passes.Size() != 0) { PassStateCache &psc = *passes[m_CurrentPassIndex]; if ((!psc.m_CallCGSetPassState) && UseStateCache) { // the matrix of the object is setup prior to the call of that method by SetValueOfUsedAutomatics -> force to update light position & direction here at the next CommitChanges // (OpenGL stores light position & direction in eye space so the matrix of the object needs to be set before a // call to glLight) // -> done twice with beginPass, but at least it works in all cases, because "ExecuteMeanings' is sometimes called // before beginPass, sometime after ... maybe is it the real problem ...?? if (psc.m_LightPositionRenderState) { m_ShaderManager->AddPassModifiedRenderState(m_CurrentPassIndex, psc.m_LightPositionRenderState); } if (psc.m_LightSpotDirectionRenderState) { m_ShaderManager->AddPassModifiedRenderState(m_CurrentPassIndex, psc.m_LightSpotDirectionRenderState); } } } } } //----------------------------------------------------------------------------- void RCKShaderCG::ExecutePerPassMeanings( CK3dEntity* iEnt, CKMaterial* iMat, CKMaterialShader* iMatShader, CKRenderContext* iRC ) { const int rcIndex = m_ShaderManager->_GetRenderContextIndex( iRC ); int techIndex = m_CurrentTechniqueIndex[rcIndex]; XASSERT(m_EffectStateCachePerContext[rcIndex]->m_StateCacheRecorded); TechniqueStateCache *tsc = m_EffectStateCachePerContext[rcIndex]->m_TechniquesStateCache[techIndex]; ShaderDescriptorCG::MeaningProcessingInfo mpi( iEnt, iMat, m_Effect[rcIndex], iRC, iMatShader, m_ShaderDescriptor[rcIndex], NULL, techIndex, true /* per pass meaning */, tsc); m_ShaderDescriptor[rcIndex]->ExecutePerPassMeanings( mpi ); } //----------------------------------------------------------------------------- int RCKShaderCG::GetAutoParameterCount( CKRenderContext* rc ) { const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc); if( !m_ShaderDescriptor[rcIndex] ) return 0; return m_ShaderDescriptor[rcIndex]->GetParamMeanings().Size(); } //----------------------------------------------------------------------------- int RCKShaderCG::GetExposedParameterCount( CKRenderContext* rc ) { const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc); if( !m_ShaderDescriptor[rcIndex] ) return 0; return m_ShaderDescriptor[rcIndex]->GetExposedParamMeanings().Size(); } //----------------------------------------------------------------------------- void RCKShaderCG::GetAutoParameterInfo( int paramIndex, ParamInfo& paramInfo, CKRenderContext* rc ) { const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc); if( !m_ShaderDescriptor[rcIndex] ) return; XArray& paramMeanings = m_ShaderDescriptor[rcIndex]->GetParamMeanings(); paramInfo.name = XString(cgGetParameterName(paramMeanings[paramIndex]->m_ParamDesc)); } //----------------------------------------------------------------------------- void RCKShaderCG::GetExposedParameterInfo( int paramIndex, ParamInfo& paramInfo, CKRenderContext* rc ) { const int rcIndex = m_ShaderManager->_GetRenderContextIndex(rc); if( !m_ShaderDescriptor[rcIndex] ) return; XArray& exposedParamMeanings = m_ShaderDescriptor[rcIndex]->GetExposedParamMeanings(); paramInfo.name = XString(cgGetParameterName(exposedParamMeanings[paramIndex]->m_ParamDesc)); paramInfo.guid = exposedParamMeanings[paramIndex]->m_Guid; } //----------------------------------------------------------------------------- bool RCKShaderCG::LinkParameters(int& CompID, XArray& params, CKBOOL cleanup) { //--- If comes from the same compilation, nothing to do. if( CompID == m_CompID ) return false; //--- Updates the compilation id. CompID = m_CompID; CKRenderManager* rm = m_ShaderManager->m_Context->GetRenderManager(); const int rcCount = m_Effect.Size(); for( int rcIndex=0 ; rcIndexGetName(); ShaderDescriptorCG::ExposedParamMeaning* paramMeaning = m_ShaderDescriptor[rcIndex]->GetParamMeaningByName( name ); //--- If parameter is found... if( paramMeaning ){ CKGUID prevGUID = p->GetGUID(); //--- If its guid has changed (for example because its annotation has changed) ///// then change its type if( !paramMeaning->m_Guid.IsValid() || prevGUID != paramMeaning->m_Guid ) { p->SetGUID( paramMeaning->m_Guid ); } //--- Kindly update UI for FLOATSLIDER because update UIMin and UIMax ///// may have changed in the shader code if( paramMeaning->m_Guid == CKPGUID_FLOATSLIDER ){ float valueToKeep = *(float*)p->GetWriteDataPtr(); ShaderDescriptorCG::MeaningProcessingInfo mpi( NULL, NULL, m_Effect[rcIndex], NULL, NULL, NULL, p, -1, false /* per pass meanings */, NULL); paramMeaning->CopyDefaultValueFromShaderToParamCB( mpi ); //--- UIMin and UIMax have been change, but we don't want the Value ///// to change so restore the previous one *(float*)p->GetWriteDataPtr() = valueToKeep; } //--- Link the ExposedMeaning* this name-matching CKParam* m_ShaderManager->_RegisterExposedParameterMeaning( params[ip], paramMeaning, rcIndex ); } else { //--- Destroy params which name does not match ///// any Exposed Meaning, and remove them from input list m_ShaderManager->m_Context->DestroyObject( p, CK_DESTROY_NONOTIFY ); m_ShaderManager->_UnregisterExposedParameter( p ); params.RemoveAt(ip); --ip; --ckParamCount; } } //--- Now parse all ExposedMeaning* and create new CKParam* ///// if there wasn't any CKParam* associated with the ExposedMeaning* XArray& exposedMeanings = m_ShaderDescriptor[rcIndex]->GetExposedParamMeanings(); const int exposedMeaningCount = exposedMeanings.Size(); for( int exposedMeaningIndex=0 ; exposedMeaningIndex_GetRegisteredParamMeaning( p, rcIndex ) == exposedMeaning ) { found=true; //--- Ensure parameter is located at the natural position if( paramIndex != exposedMeaningIndex ){ //--- And if not, then move it to the desired position params.Move( ¶ms[exposedMeaningIndex], ¶ms[paramIndex] ); } break; } } //--- No CKParam* linked to the ExposedMeaning*, so create one if( !found ){ //--- So let's create a new CKParameter CKParameterLocal* p = m_ShaderManager->m_Context->CreateCKParameterLocal( (char*)cgGetParameterName(exposedMeaning->m_ParamDesc), exposedMeaning->m_Guid ); //--- Insert it in the CKParameter array at the natural position if possible if( params.Size() > exposedMeaningIndex ){ params.Insert( exposedMeaningIndex, p ); } else { params.PushBack(p); } m_ShaderManager->_RegisterExposedParameterMeaning( p, exposedMeaning, rcIndex ); //--- We must register the parameter for the others handles ///// of all other render context, to make sure no other local param ///// will be created (as we must have only 1 ckparam for all RCs) for( int otherRCIndex=0 ; otherRCIndex& exposedMeaningsOfOtherRC = m_ShaderDescriptor[otherRCIndex]->GetExposedParamMeanings(); ShaderDescriptorCG::ExposedParamMeaning* meaningOfOtherRC = exposedMeaningsOfOtherRC[ exposedMeaningIndex ]; m_ShaderManager->_RegisterExposedParameterMeaning( p, meaningOfOtherRC, otherRCIndex ); } //--- While we are at it, tries to give the brand new parameter ///// the same value as the one in the shader. ///// Note: In principle, for the CopyDefaultValue callback we only need ///// to provide the FX and the CKParam ShaderDescriptorCG::MeaningProcessingInfo mpi( NULL, NULL, m_Effect[rcIndex], NULL, NULL, NULL, p, -1, false/* per pass meanings */, NULL); exposedMeaning->CopyDefaultValueFromShaderToParamCB( mpi ); } } } return true; } //----------------------------------------------------------------------------- bool RCKShaderCG::LinkTechnique( int& CompID, const XString& iTechName, BOOL iFNVT, int& oTechIndex ) { //--- If comes from the same compilation, nothing to do. if( CompID == m_CompID ) return false; //--- Updates the compilation id. CompID = m_CompID; //--- Retrieves Technique index From Name if( !GetTechIndexByName( iTechName, oTechIndex ) ) return false; //--- Finds the next valid technique. if( iFNVT ){ return FindNextValidTechnique( oTechIndex ); } return true; } //----------------------------------------------------------------------------- void RCKShaderCG::ClearStateCache() { int contextCount = m_EffectStateCachePerContext.Size(); for (int contextIndex = 0; contextIndex < contextCount; ++contextIndex) { m_EffectStateCachePerContext[contextIndex]->Clear(); } } //----------------------------------------------------------------------------- void RCKShaderCG::RecordStates() { ClearStateCache(); int contextCount = m_EffectStateCachePerContext.Size(); for (int contextIndex = 0; contextIndex < contextCount; ++contextIndex) { m_EffectStateCachePerContext[contextIndex]->Clear(); EffectStateCache &efsc = *m_EffectStateCachePerContext[contextCount]; XASSERT(!efsc.m_StateCacheRecorded); RecordEffectStates(m_Effect[contextIndex], m_ShaderDescriptor[contextIndex], efsc); } } //----------------------------------------------------------------------------- // Compiling //----------------------------------------------------------------------------- void RCKShaderCG::Compile(CKContext* Context) { XClassArray output; m_ShaderManager->CompileShader(this, output); RecordStates(); } //----------------------------------------------------------------------------- void RCKShaderCG::_AddRenderContextSlot() { //--- Add a Effect slot m_Effect.PushBack( NULL ); m_CurrentTechnique.PushBack( NULL ); m_CurrentTechniqueIndex.PushBack(0); m_EffectStateCachePerContext.PushBack(new EffectStateCache()); passArray p; m_CurrentActivePass.PushBack(p); ///// Also add a ShaderDescriptorCG slot ShaderDescriptorCG::ShaderCG* shaderDescriptorForThisRenderContext = new ShaderDescriptorCG::ShaderCG; m_ShaderDescriptor.PushBack( shaderDescriptorForThisRenderContext ); } //----------------------------------------------------------------------------- void RCKShaderCG::_RemoveRenderContextSlot( int iRCIndex ) { //--- Remove dxEffect for this rcIndex XArray& dxEffectArray = m_Effect; dxEffectArray.RemoveAt( iRCIndex ); m_CurrentTechnique.RemoveAt( iRCIndex ); m_CurrentTechniqueIndex.RemoveAt( iRCIndex ); delete m_EffectStateCachePerContext[iRCIndex]; m_EffectStateCachePerContext.RemoveAt(iRCIndex); m_CurrentActivePass.RemoveAt(iRCIndex); //--- Remove also the ShaderDescriptorCG delete m_ShaderDescriptor[iRCIndex]; m_ShaderDescriptor.RemoveAt( iRCIndex ); } //----------------------------------------------------------------------------- // Registering //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- CKSTRING RCKShaderCG::GetClassName() { return "Shader"; } //----------------------------------------------------------------------------- // Render state caches //----------------------------------------------------------------------------- //----------------------------------------------------------------------------------- void CachedRenderStateBool::Apply(CKRasterizerContext *rc, bool doReset) { if (doReset) { Callback(rc, *this, &DefaultValue[0], true); } else { if (NeedReeval) { int valueCount; const CGbool *values = cgGetBoolStateAssignmentValues(StateAssignment, &valueCount); if (valueCount <= sizeofarray(StaticValue)) { for (int i = 0; i < valueCount; ++i) { StaticValue[i] = values[i]; } NeedReeval = false; } else { // can't store value ... just pass through Callback(rc, *this, values, false); return; } } // callback for that state Callback(rc, *this, &StaticValue[0], false); } } //----------------------------------------------------------------------------------- void CachedRenderStateInt::Apply(CKRasterizerContext *rc, bool doReset) { if (doReset) { Callback(rc, *this, &DefaultValue[0], true); } else { if (NeedReeval) { int valueCount; const int *values = cgGetIntStateAssignmentValues(StateAssignment, &valueCount); if (valueCount <= sizeofarray(StaticValue)) { for (int i = 0; i < valueCount; ++i) { StaticValue[i] = values[i]; } NeedReeval = false; } else { // can't store value ... just pass through Callback(rc, *this, values, false); return; } } // callback for that state Callback(rc, *this, &StaticValue[0], false); } } //----------------------------------------------------------------------------------- void CachedRenderStateFloat::Apply(CKRasterizerContext *rc, bool doReset) { if (doReset) { Callback(rc, *this, &DefaultValue[0], true); } else { if (NeedReeval) { int valueCount; const float *values = cgGetFloatStateAssignmentValues(StateAssignment, &valueCount); if (valueCount <= sizeofarray(StaticValue)) { for (int i = 0; i < valueCount; ++i) { StaticValue[i] = values[i]; } NeedReeval = false; } else { // can't store value ... just pass through Callback(rc, *this, values, false); return; } } // callback for that state Callback(rc, *this, &StaticValue[0], false); } } //----------------------------------------------------------------------------------- void CachedRenderStateProgram::Apply(CKRasterizerContext *rc, bool doReset) { if (doReset) { Callback(rc, *this, &DefaultValue[0], true); } else { if (NeedReeval) { CGprogram prog = cgGetProgramStateAssignmentValue(StateAssignment); StaticValue[0] = prog; } // callback for that state Callback(rc, *this, &StaticValue[0], false); } }