ID3DBlob *ShaderLanguageHlsl::loadShader(const char *shaderModel, const char *shaderSource, const char *entryPoint) const { // Get compile flags UINT compileFlags = D3DCOMPILE_ENABLE_STRICTNESS; switch (getOptimizationLevel()) { case OptimizationLevel::Debug: compileFlags |= D3DCOMPILE_DEBUG; compileFlags |= D3DCOMPILE_SKIP_OPTIMIZATION; break; case OptimizationLevel::None: compileFlags |= D3DCOMPILE_SKIP_VALIDATION; compileFlags |= D3DCOMPILE_SKIP_OPTIMIZATION; break; case OptimizationLevel::Low: compileFlags |= D3DCOMPILE_SKIP_VALIDATION; compileFlags |= D3DCOMPILE_OPTIMIZATION_LEVEL0; break; case OptimizationLevel::Medium: compileFlags |= D3DCOMPILE_SKIP_VALIDATION; compileFlags |= D3DCOMPILE_OPTIMIZATION_LEVEL1; break; case OptimizationLevel::High: compileFlags |= D3DCOMPILE_SKIP_VALIDATION; compileFlags |= D3DCOMPILE_OPTIMIZATION_LEVEL2; break; case OptimizationLevel::Ultra: compileFlags |= D3DCOMPILE_OPTIMIZATION_LEVEL3; break; } ID3DBlob *d3dBlob = nullptr; ID3DBlob *errorBlob = nullptr; if (FAILED(D3DX10CompileFromMemory(shaderSource, strlen(shaderSource), nullptr, nullptr, nullptr, entryPoint ? entryPoint : "main", shaderModel, compileFlags, 0, nullptr, &d3dBlob, &errorBlob, nullptr))) { if (nullptr != errorBlob) { ::OutputDebugStringA(static_cast<char*>(errorBlob->GetBufferPointer())); errorBlob->Release(); } // Error! return nullptr; } if (nullptr != errorBlob) { errorBlob->Release(); } // Done return d3dBlob; }
bool CShaderHLSL::Create(P3D::sShaderDesc &desc) { const char *pData; ULONG fsize; IFileSystem* pFS = CRenderer::mEngine()->mFilesystem(); wchar path[P3DMAX_PATH]; wsprintf(path, P3DMAX_PATH-1, _W("shaders/%s.rshader"), desc.ShaderFile.Get()); FSFILE *fp = pFS->Load(path, (BYTE *&)pData, fsize, true); if (!fp) { CON(MSG_ERR, _W("Can't open %s.hlsl shader file from data/shaders directory!"), desc.ShaderFile.Get()); return false; } ID3D10Blob *pShaderBlob = NULL; ID3D10Blob *pErrors = NULL; UINT flags = D3D10_SHADER_DEBUG; //D3D10_SHADER_OPTIMIZATION_LEVEL3 char profile[128]; switch(desc.ShaderType) { case SHADERTYPE_VERTEX_SHADER: strcpy(profile, D3D10GetVertexShaderProfile(g_pD3ddev)); break; case SHADERTYPE_GEOMETRY_SHADER: strcpy(profile, D3D10GetGeometryShaderProfile(g_pD3ddev)); break; case SHADERTYPE_PIXEL_SHADER: strcpy(profile, D3D10GetPixelShaderProfile(g_pD3ddev)); break; default: CON(MSG_ERR, _W("Chader creation failed. No apropriate ShaderType given.")); return false; } CIncludeHandler includeHandler; D3D10_SHADER_MACRO Shader_Macros[] = { { "DX10", NULL }, { "SM4", NULL }, NULL }; if(!CheckHRResult(D3DX10CompileFromMemory( pData, fsize, NULL, Shader_Macros, &includeHandler, _W2A(desc.EntryFunction.Get()), profile, flags, 0, NULL, &pShaderBlob, &pErrors, NULL ))) { if(pErrors) CON(MSG_ERR, _W("%s"), _A2W((char*)pErrors->GetBufferPointer())); else CON(MSG_ERR, _W("Error description not given")); CON(MSG_ERR, _W("Shader %s could not be compiled"), desc.ShaderFile.Get()); SAFE_RELEASE(pErrors); return false; } pFS->UnLoad(fp, (BYTE *)pData); //save to cache fp = pFS->Open(_W("cache/shaders/hlsl"), _W("wb")); const char* cs = (const char*)pShaderBlob->GetBufferPointer(); pFS->Write(cs, 1, pShaderBlob->GetBufferSize(), fp); pFS->Close(fp); bool shaderCreated = false; switch(desc.ShaderType) { case SHADERTYPE_VERTEX_SHADER: shaderCreated = CheckHRResult(g_pD3ddev->CreateVertexShader(pShaderBlob->GetBufferPointer(), pShaderBlob->GetBufferSize(), &m_pVS)); break; case SHADERTYPE_GEOMETRY_SHADER: shaderCreated = CheckHRResult(g_pD3ddev->CreateGeometryShader(pShaderBlob->GetBufferPointer(), pShaderBlob->GetBufferSize(), &m_pGS)); break; case SHADERTYPE_PIXEL_SHADER: shaderCreated = CheckHRResult(g_pD3ddev->CreatePixelShader(pShaderBlob->GetBufferPointer(), pShaderBlob->GetBufferSize(), &m_pPS)); break; } if(!shaderCreated) { CON(MSG_ERR, _W("Shader creation error")); return false; } //if(!CheckHRResult(D3DReflect((DWORD*)pShaderBlob->GetBufferPointer(), pShaderBlob->GetBufferSize(), __uuidof(ID3D10ShaderReflection), &m_pReflection))) if(!CheckHRResult(D3D10ReflectShader(pShaderBlob->GetBufferPointer(), pShaderBlob->GetBufferSize(), &m_pReflection))) { CON(MSG_ERR, _W("Could not create a Shader reflection")); return false; } //HRESULT D3DReflect(LPCVOID pSrcData, SIZE_T SrcDataSize, REFIID pInterface, void **ppReflector); D3D10_SHADER_DESC shDesc; m_pReflection->GetDesc(&shDesc); m_numResources = shDesc.BoundResources; //not sure about this if(desc.ShaderType == SHADERTYPE_VERTEX_SHADER) m_pVertDecl = new CVertexDeclaration(CRenderer::cGraphicsManager()->GetVertexDescByID(desc.VertexDescID), pShaderBlob); SAFE_RELEASE(pShaderBlob); m_desc = desc; CON(MSG_INFO, _W("Shader '%s' created"), desc.ShaderFile); return true; }
Shader* D3D10VertexShader::CreateVertexShader(CTSTR lpShader, CTSTR lpFileName) { String errorString; ShaderProcessor shaderProcessor; if(!shaderProcessor.ProcessShader(lpShader, lpFileName)) AppWarning(TEXT("Unable to process vertex shader '%s'"), lpFileName); //don't exit, leave it to the actual shader compiler to tell the errors //----------------------------------------------- LPSTR lpAnsiShader = tstr_createUTF8(lpShader); LPSTR lpAnsiFileName = tstr_createUTF8(lpFileName); D3D10System *d3d10Sys = static_cast<D3D10System*>(GS); LPCSTR lpVSType = d3d10Sys->bDisableCompatibilityMode ? "vs_4_0" : "vs_4_0_level_9_3"; ID3D10Blob *errorMessages = NULL, *shaderBlob = NULL; HRESULT err = D3DX10CompileFromMemory(lpAnsiShader, strlen(lpAnsiShader), lpAnsiFileName, NULL, NULL, "main", lpVSType, D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, NULL, &shaderBlob, &errorMessages, NULL); Free(lpAnsiFileName); Free(lpAnsiShader); if(FAILED(err)) { if(errorMessages) { if(errorMessages->GetBufferSize()) { LPSTR lpErrors = (LPSTR)errorMessages->GetBufferPointer(); Log(TEXT("Error compiling vertex shader '%s':\r\n\r\n%S\r\n"), lpFileName, lpErrors); } errorMessages->Release(); } CrashError(TEXT("Compilation of vertex shader '%s' failed, result = %08lX"), lpFileName, err); return NULL; } //----------------------------------------------- ID3D10VertexShader *vShader; ID3D10InputLayout *vShaderLayout; err = GetD3D()->CreateVertexShader(shaderBlob->GetBufferPointer(), shaderBlob->GetBufferSize(), &vShader); if(FAILED(err)) { CrashError(TEXT("Unable to create vertex shader '%s', result = %08lX"), lpFileName, err); SafeRelease(shaderBlob); return NULL; } err = GetD3D()->CreateInputLayout(shaderProcessor.generatedLayout.Array(), shaderProcessor.generatedLayout.Num(), shaderBlob->GetBufferPointer(), shaderBlob->GetBufferSize(), &vShaderLayout); if(FAILED(err)) { CrashError(TEXT("Unable to create vertex layout for vertex shader '%s', result = %08lX"), lpFileName, err); SafeRelease(shaderBlob); SafeRelease(vShader); return NULL; } shaderBlob->Release(); //----------------------------------------------- D3D10VertexShader *shader = new D3D10VertexShader; shader->vertexShader = vShader; shader->inputLayout = vShaderLayout; if(!shader->ProcessData(shaderProcessor, lpFileName)) { delete shader; return NULL; } shader->bHasNormals = shaderProcessor.bHasNormals; shader->bHasColors = shaderProcessor.bHasColors; shader->bHasTangents = shaderProcessor.bHasTangents; shader->nTextureCoords = shaderProcessor.numTextureCoords; shader->hViewProj = shader->GetParameterByName(TEXT("ViewProj")); return shader; }
Shader* D3D10PixelShader::CreatePixelShader(CTSTR lpShader, CTSTR lpFileName) { String errorString; ShaderProcessor shaderProcessor; if(!shaderProcessor.ProcessShader(lpShader, lpFileName)) AppWarning(TEXT("Unable to process pixel shader '%s'"), lpFileName); //don't exit, leave it to the actual shader compiler to tell the errors //----------------------------------------------- LPSTR lpAnsiShader = tstr_createUTF8(lpShader); LPSTR lpAnsiFileName = tstr_createUTF8(lpFileName); D3D10System *d3d10Sys = static_cast<D3D10System*>(GS); LPCSTR lpPSType = d3d10Sys->bDisableCompatibilityMode ? "ps_4_0" : "ps_4_0_level_9_3"; ID3D10Blob *errorMessages = NULL, *shaderBlob = NULL; HRESULT err = D3DX10CompileFromMemory(lpAnsiShader, strlen(lpAnsiShader), lpAnsiFileName, NULL, NULL, "main", lpPSType, D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, NULL, &shaderBlob, &errorMessages, NULL); Free(lpAnsiFileName); Free(lpAnsiShader); if(FAILED(err)) { if(errorMessages) { if(errorMessages->GetBufferSize()) { LPSTR lpErrors = (LPSTR)errorMessages->GetBufferPointer(); Log(TEXT("Error compiling pixel shader '%s':\r\n\r\n%S\r\n"), lpFileName, lpErrors); } errorMessages->Release(); } CrashError(TEXT("Compilation of pixel shader '%s' failed, result = %08lX"), lpFileName, err); return NULL; } //----------------------------------------------- ID3D10PixelShader *pShader; err = GetD3D()->CreatePixelShader(shaderBlob->GetBufferPointer(), shaderBlob->GetBufferSize(), &pShader); if(FAILED(err)) { CrashError(TEXT("Unable to create pixel shader '%s', result = %08lX"), lpFileName, err); SafeRelease(shaderBlob); return NULL; } shaderBlob->Release(); //----------------------------------------------- D3D10PixelShader *shader = new D3D10PixelShader; shader->pixelShader = pShader; if(!shader->ProcessData(shaderProcessor, lpFileName)) { delete shader; return NULL; } return shader; }
Shader* D3D10VertexShader::CreateVertexShader(CTSTR lpShader, CTSTR lpFileName) { String errorString; ShaderProcessor shaderProcessor; if(!shaderProcessor.ProcessShader(lpShader, lpFileName)) AppWarning(TEXT("Unable to process vertex shader '%s'"), lpFileName); //don't exit, leave it to the actual shader compiler to tell the errors //----------------------------------------------- D3D10System *d3d10Sys = static_cast<D3D10System*>(GS); LPCSTR lpVSType = d3d10Sys->bDisableCompatibilityMode ? "vs_4_0" : "vs_4_0_level_9_3"; String cacheFilename = FormattedString(TEXT("%s/shaderCache/%s.blob"), OBSGetAppDataPath(), lpFileName).FindReplace(TEXT("\\"), TEXT("/")); List<BYTE> shaderBuffer; LPVOID shaderData; SIZE_T shaderDataSize; ID3D10Blob *errorMessages = NULL, *shaderBlob = NULL; HRESULT err; if(!OSFileExists(cacheFilename) || OSGetFileModificationTime(lpFileName) > OSGetFileModificationTime(cacheFilename)) { LPSTR lpAnsiShader = tstr_createUTF8(lpShader); LPSTR lpAnsiFileName = tstr_createUTF8(lpFileName); err = D3DX10CompileFromMemory(lpAnsiShader, strlen(lpAnsiShader), lpAnsiFileName, NULL, NULL, "main", lpVSType, D3D10_SHADER_OPTIMIZATION_LEVEL3, 0, NULL, &shaderBlob, &errorMessages, NULL); Free(lpAnsiFileName); Free(lpAnsiShader); if(FAILED(err)) { if(errorMessages) { if(errorMessages->GetBufferSize()) { LPSTR lpErrors = (LPSTR)errorMessages->GetBufferPointer(); Log(TEXT("Error compiling vertex shader '%s':\r\n\r\n%S\r\n"), lpFileName, lpErrors); } errorMessages->Release(); } CrashError(TEXT("Compilation of vertex shader '%s' failed, result = %08lX"), lpFileName, err); return NULL; } shaderData = shaderBlob->GetBufferPointer(); shaderDataSize = shaderBlob->GetBufferSize(); CreatePath(GetPathDirectory(cacheFilename)); XFile cacheFile(cacheFilename, XFILE_WRITE, XFILE_CREATEALWAYS); cacheFile.Write(shaderData, (DWORD)shaderDataSize); } else { XFile cacheFile(cacheFilename, XFILE_READ | XFILE_SHARED, XFILE_OPENEXISTING); shaderBuffer.SetSize((unsigned)cacheFile.GetFileSize()); cacheFile.Read(shaderBuffer.Array(), shaderBuffer.Num()); shaderData = shaderBuffer.Array(); shaderDataSize = shaderBuffer.Num(); } //----------------------------------------------- ID3D10VertexShader *vShader; ID3D10InputLayout *vShaderLayout; err = GetD3D()->CreateVertexShader(shaderData, shaderDataSize, &vShader); if(FAILED(err)) { CrashError(TEXT("Unable to create vertex shader '%s', result = %08lX"), lpFileName, err); SafeRelease(shaderBlob); return NULL; } err = GetD3D()->CreateInputLayout(shaderProcessor.generatedLayout.Array(), shaderProcessor.generatedLayout.Num(), shaderData, shaderDataSize, &vShaderLayout); if(FAILED(err)) { CrashError(TEXT("Unable to create vertex layout for vertex shader '%s', result = %08lX"), lpFileName, err); SafeRelease(shaderBlob); SafeRelease(vShader); return NULL; } SafeRelease(shaderBlob); //----------------------------------------------- D3D10VertexShader *shader = new D3D10VertexShader; shader->vertexShader = vShader; shader->inputLayout = vShaderLayout; if(!shader->ProcessData(shaderProcessor, lpFileName)) { delete shader; return NULL; } shader->bHasNormals = shaderProcessor.bHasNormals; shader->bHasColors = shaderProcessor.bHasColors; shader->bHasTangents = shaderProcessor.bHasTangents; shader->nTextureCoords = shaderProcessor.numTextureCoords; shader->hViewProj = shader->GetParameterByName(TEXT("ViewProj")); return shader; }
//----------------------------------------------------------------------- void D3D10HLSLProgram::loadFromSource(void) { class HLSLIncludeHandler : public ID3D10Include { public: HLSLIncludeHandler(Resource* sourceProgram) : mProgram(sourceProgram) {} ~HLSLIncludeHandler() {} STDMETHOD(Open)(D3D10_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID *ppData, UINT *pByteLen ) { // find & load source code DataStreamPtr stream = ResourceGroupManager::getSingleton().openResource( String(pFileName), mProgram->getGroup(), true, mProgram); String source = stream->getAsString(); // copy into separate c-string // Note - must NOT copy the null terminator, otherwise this will terminate // the entire program string! *pByteLen = static_cast<UINT>(source.length()); char* pChar = new char[*pByteLen]; memcpy(pChar, source.c_str(), *pByteLen); *ppData = pChar; return S_OK; } STDMETHOD(Close)(LPCVOID pData) { char* pChar = (char*)pData; delete [] pChar; return S_OK; } protected: Resource* mProgram; }; // include handler HLSLIncludeHandler includeHandler(this); ID3D10Blob * errors = 0; /*String profile; // Instruction set to be used when generating code. Possible values: "vs_4_0", "ps_4_0", or "gs_4_0". switch(mType) { case GPT_VERTEX_PROGRAM: profile = "vs_4_0"; break; case GPT_FRAGMENT_PROGRAM: profile = "ps_4_0"; break; }*/ HRESULT hr = D3DX10CompileFromMemory( mSource.c_str(), // [in] Pointer to the shader in memory. mSource.size(), // [in] Size of the shader in memory. NULL, // [in] The name of the file that contains the shader code. NULL, // [in] Optional. Pointer to a NULL-terminated array of macro definitions. See D3D10_SHADER_MACRO. If not used, set this to NULL. &includeHandler, // [in] Optional. Pointer to an ID3D10Include Interface interface for handling include files. Setting this to NULL will cause a compile error if a shader contains a #include. mEntryPoint.c_str(), // [in] Name of the shader-entrypoint function where shader execution begins. mTarget.c_str(), // [in] A string that specifies the shader model; can be any profile in shader model 2, shader model 3, or shader model 4. 0, // [in] Effect compile flags - no D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY at the first try... NULL, // [in] Effect compile flags NULL, // [in] A pointer to a thread pump interface (see ID3DX10ThreadPump Interface). Use NULL to specify that this function should not return until it is completed. &mpMicroCode, // [out] A pointer to an ID3D10Blob Interface which contains the compiled shader, as well as any embedded debug and symbol-table information. &errors, // [out] A pointer to an ID3D10Blob Interface which contains a listing of errors and warnings that occured during compilation. These errors and warnings are identical to the the debug output from a debugger. NULL // [out] A pointer to the return value. May be NULL. If pPump is not NULL, then pHResult must be a valid memory location until the asynchronous execution completes. ); if (FAILED(hr)) // if fails - try with backwards compatibility flag { hr = D3DX10CompileFromMemory( mSource.c_str(), // [in] Pointer to the shader in memory. mSource.size(), // [in] Size of the shader in memory. NULL, // [in] The name of the file that contains the shader code. NULL, // [in] Optional. Pointer to a NULL-terminated array of macro definitions. See D3D10_SHADER_MACRO. If not used, set this to NULL. &includeHandler, // [in] Optional. Pointer to an ID3D10Include Interface interface for handling include files. Setting this to NULL will cause a compile error if a shader contains a #include. mEntryPoint.c_str(), // [in] Name of the shader-entrypoint function where shader execution begins. mTarget.c_str(), // [in] A string that specifies the shader model; can be any profile in shader model 2, shader model 3, or shader model 4. D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY, // [in] Effect compile flags - D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY enables older shaders to compile to 4_0 targets NULL, // [in] Effect compile flags NULL, // [in] A pointer to a thread pump interface (see ID3DX10ThreadPump Interface). Use NULL to specify that this function should not return until it is completed. &mpMicroCode, // [out] A pointer to an ID3D10Blob Interface which contains the compiled shader, as well as any embedded debug and symbol-table information. &errors, // [out] A pointer to an ID3D10Blob Interface which contains a listing of errors and warnings that occured during compilation. These errors and warnings are identical to the the debug output from a debugger. NULL // [out] A pointer to the return value. May be NULL. If pPump is not NULL, then pHResult must be a valid memory location until the asynchronous execution completes. ); } #if 0 // this is how you disassemble LPCSTR commentString = NULL; ID3D10Blob* pIDisassembly = NULL; char* pDisassembly = NULL; if( mpMicroCode ) { D3D10DisassembleShader( (UINT*) mpMicroCode->GetBufferPointer(), mpMicroCode->GetBufferSize(), TRUE, commentString, &pIDisassembly ); } const char* assemblyCode = static_cast<const char*>(pIDisassembly->GetBufferPointer()); #endif if (FAILED(hr)) { mErrorsInCompile = true; String message = "Cannot assemble D3D10 high-level shader " + mName + " Errors:\n" + static_cast<const char*>(errors->GetBufferPointer()); errors->Release(); OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, message, "D3D10HLSLProgram::loadFromSource"); } SIZE_T BytecodeLength = mpMicroCode->GetBufferSize(); // this is a temp patch for the nov 08 DX SDK #ifdef D3DX10ReflectShader hr = D3DX10ReflectShader( (void*) mpMicroCode->GetBufferPointer(), BytecodeLength, &mpIShaderReflection ); #else hr = D3D10ReflectShader( (void*) mpMicroCode->GetBufferPointer(), BytecodeLength, &mpIShaderReflection ); #endif if (!FAILED(hr)) { hr = mpIShaderReflection->GetDesc( &mShaderDesc ); if (!FAILED(hr)) { if (mShaderDesc.ConstantBuffers == 1) { mShaderReflectionConstantBuffer = mpIShaderReflection->GetConstantBufferByIndex(0); hr = mShaderReflectionConstantBuffer->GetDesc(&mConstantBufferDesc); createConstantBuffer(mConstantBufferDesc.Size); for(unsigned int i = 0; i < mConstantBufferDesc.Variables ; i++) { ID3D10ShaderReflectionVariable* varRef; varRef = mShaderReflectionConstantBuffer->GetVariableByIndex(i); D3D10_SHADER_VARIABLE_DESC shaderVerDesc; HRESULT hr = varRef->GetDesc(&shaderVerDesc); ShaderVarWithPosInBuf newVar; newVar.var = shaderVerDesc; newVar.wasInit = false; mShaderVars.push_back(newVar); } } } } switch(mType) { case GPT_VERTEX_PROGRAM: CreateVertexShader(); break; case GPT_FRAGMENT_PROGRAM: CreatePixelShader(); break; } }