diff --git a/src/Layers/xrRenderPC_GL/rgl.cpp b/src/Layers/xrRenderPC_GL/rgl.cpp index f324e8f030d..2f58f73e6f0 100644 --- a/src/Layers/xrRenderPC_GL/rgl.cpp +++ b/src/Layers/xrRenderPC_GL/rgl.cpp @@ -1,5 +1,4 @@ #include "stdafx.h" - #include "rgl.h" #include "Layers/xrRender/FBasicVisual.h" #include "xrEngine/xr_object.h" @@ -704,667 +703,3 @@ void CRender::DumpStatistics(IGameFont& font, IPerformanceAlert* alert) Stats.FrameStart(); HOM.DumpStatistics(font, alert); } - -void CRender::addShaderOption(const char* name, const char* value) -{ - m_ShaderOptions += "#define "; - m_ShaderOptions += name; - m_ShaderOptions += " "; - m_ShaderOptions += value; - m_ShaderOptions += "\n"; -} - -static inline bool match_shader_id(LPCSTR const debug_shader_id, LPCSTR const full_shader_id, - FS_FileSet const& file_set, string_path& result); - -///////// - -static inline void load_includes(LPCSTR pSrcData, UINT SrcDataLen, xr_vector& source, xr_vector& includes) -{ - // Copy source file data into a null-terminated buffer - char* srcData = xr_alloc(SrcDataLen + 2); - memcpy(srcData, pSrcData, SrcDataLen); - srcData[SrcDataLen] = '\n'; - srcData[SrcDataLen + 1] = '\0'; - includes.push_back(srcData); - source.push_back(srcData); - - string_path path; - char* str = srcData; - while (strstr(str, "#include") != nullptr) - { - // Get filename of include directive - str = strstr(str, "#include"); // Find the include directive - char* fn = strchr(str, '"') + 1; // Get filename, skip quotation - *str = '\0'; // Terminate previous source - str = strchr(fn, '"'); // Get end of filename path - *str = '\0'; // Terminate filename path - - // Create path to included shader - strconcat(sizeof path, path, GEnv.Render->getShaderPath(), fn); - FS.update_path(path, "$game_shaders$", path); - while (char* sep = strchr(path, '/')) *sep = '\\'; - - // Open and read file, recursively load includes - IReader* R = FS.r_open(path); - R_ASSERT2(R, path); - load_includes((char*)R->pointer(), R->length(), source, includes); - FS.r_close(R); - - // Add next source, skip quotation - str++; - source.push_back(str); - } -} - -struct SHADER_MACRO -{ - char *Define = "#define ", *Name = "\n", *Sep = "\t", *Definition = "\n", *EOL = "\n"; -}; - -HRESULT CRender::shader_compile( - LPCSTR name, - DWORD const* pSrcData, - UINT SrcDataLen, - LPCSTR pFunctionName, - LPCSTR pTarget, - DWORD Flags, - void*& result) -{ - xr_vector source, includes; - SHADER_MACRO defines[128]; - int def_it = 0; - char c_smapsize[32]; - char c_gloss[32]; - char c_sun_shafts[32]; - char c_ssao[32]; - char c_sun_quality[32]; - - // TODO: OGL: Implement these parameters. - VERIFY(!pFunctionName); - VERIFY(!pTarget); - VERIFY(!Flags); - - // open included files - load_includes((LPCSTR)pSrcData, SrcDataLen, source, includes); - - char sh_name[MAX_PATH] = ""; - u32 len = 0; - // options - { - xr_sprintf(c_smapsize, "%04d", u32(o.smapsize)); - defines[def_it].Name = "SMAP_size"; - defines[def_it].Definition = c_smapsize; - def_it++; - VERIFY(xr_strlen(c_smapsize) == 4); - xr_strcat(sh_name, c_smapsize); - len += 4; - } - - if (o.fp16_filter) - { - defines[def_it].Name = "FP16_FILTER"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.fp16_filter); - ++len; - - if (o.fp16_blend) - { - defines[def_it].Name = "FP16_BLEND"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.fp16_blend); - ++len; - - if (o.HW_smap) - { - defines[def_it].Name = "USE_HWSMAP"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.HW_smap); - ++len; - - if (o.HW_smap_PCF) - { - defines[def_it].Name = "USE_HWSMAP_PCF"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.HW_smap_PCF); - ++len; - - if (o.HW_smap_FETCH4) - { - defines[def_it].Name = "USE_FETCH4"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.HW_smap_FETCH4); - ++len; - - if (o.sjitter) - { - defines[def_it].Name = "USE_SJITTER"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.sjitter); - ++len; - - if (HW.Caps.raster_major >= 3) - { - defines[def_it].Name = "USE_BRANCHING"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(HW.Caps.raster_major >= 3); - ++len; - - if (HW.Caps.geometry.bVTF) - { - defines[def_it].Name = "USE_VTF"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(HW.Caps.geometry.bVTF); - ++len; - - if (o.Tshadows) - { - defines[def_it].Name = "USE_TSHADOWS"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.Tshadows); - ++len; - - if (o.mblur) - { - defines[def_it].Name = "USE_MBLUR"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.mblur); - ++len; - - if (o.sunfilter) - { - defines[def_it].Name = "USE_SUNFILTER"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.sunfilter); - ++len; - - if (o.sunstatic) - { - defines[def_it].Name = "USE_R2_STATIC_SUN"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.sunstatic); - ++len; - - if (o.forcegloss) - { - xr_sprintf(c_gloss, "%f", o.forcegloss_v); - defines[def_it].Name = "FORCE_GLOSS"; - defines[def_it].Definition = c_gloss; - def_it++; - } - sh_name[len] = '0' + char(o.forcegloss); - ++len; - - if (o.forceskinw) - { - defines[def_it].Name = "SKIN_COLOR"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.forceskinw); - ++len; - - if (o.ssao_blur_on) - { - defines[def_it].Name = "USE_SSAO_BLUR"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.ssao_blur_on); - ++len; - - if (o.ssao_hdao) - { - defines[def_it].Name = "HDAO"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.ssao_hdao); - ++len; - - if (o.ssao_hbao) - { - defines[def_it].Name = "USE_HBAO"; - defines[def_it].Definition = "1"; - def_it++; - if (o.hbao_vectorized) - { - defines[def_it].Name = "VECTORIZED_CODE"; - defines[def_it].Definition = "1"; - def_it++; - } - } - sh_name[len] = '0' + char(o.ssao_hbao); - ++len; - sh_name[len] = '0' + char(o.ssao_hbao ? o.hbao_vectorized : 0); - ++len; - - if (o.ssao_opt_data) - { - defines[def_it].Name = "SSAO_OPT_DATA"; - if (o.ssao_half_data) - defines[def_it].Definition = "2"; - else - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.ssao_opt_data ? (o.ssao_half_data ? 2 : 1) : 0); - ++len; - - // skinning - if (m_skinning < 0) - { - defines[def_it].Name = "SKIN_NONE"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (0 == m_skinning) - { - defines[def_it].Name = "SKIN_0"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(0 == m_skinning); - ++len; - - if (1 == m_skinning) - { - defines[def_it].Name = "SKIN_1"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(1 == m_skinning); - ++len; - - if (2 == m_skinning) - { - defines[def_it].Name = "SKIN_2"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(2 == m_skinning); - ++len; - - if (3 == m_skinning) - { - defines[def_it].Name = "SKIN_3"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(3 == m_skinning); - ++len; - - if (4 == m_skinning) - { - defines[def_it].Name = "SKIN_4"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(4 == m_skinning); - ++len; - - // Igor: need restart options - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_WATER)) - { - defines[def_it].Name = "USE_SOFT_WATER"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_PARTICLES)) - { - defines[def_it].Name = "USE_SOFT_PARTICLES"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_DOF)) - { - defines[def_it].Name = "USE_DOF"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r_sun_shafts) - { - xr_sprintf(c_sun_shafts, "%d", ps_r_sun_shafts); - defines[def_it].Name = "SUN_SHAFTS_QUALITY"; - defines[def_it].Definition = c_sun_shafts; - def_it++; - sh_name[len] = '0' + char(ps_r_sun_shafts); - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r_ssao) - { - xr_sprintf(c_ssao, "%d", ps_r_ssao); - defines[def_it].Name = "SSAO_QUALITY"; - defines[def_it].Definition = c_ssao; - def_it++; - sh_name[len] = '0' + char(ps_r_ssao); - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r_sun_quality) - { - xr_sprintf(c_sun_quality, "%d", ps_r_sun_quality); - defines[def_it].Name = "SUN_QUALITY"; - defines[def_it].Definition = c_sun_quality; - def_it++; - sh_name[len] = '0' + char(ps_r_sun_quality); - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_STEEP_PARALLAX)) - { - defines[def_it].Name = "ALLOW_STEEPPARALLAX"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (o.dx10_gbuffer_opt) - { - defines[def_it].Name = "GBUFFER_OPTIMIZATION"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.dx10_gbuffer_opt); - ++len; - - if (o.dx10_sm4_1) - { - defines[def_it].Name = "SM_4_1"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.dx10_sm4_1); - ++len; - - if (o.dx10_minmax_sm) - { - defines[def_it].Name = "USE_MINMAX_SM"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.dx10_minmax_sm != 0); - ++len; - - // add a #define for DX10_1 MSAA support - if (o.dx10_msaa) - { - static char samples[2]; - - defines[def_it].Name = "USE_MSAA"; - defines[def_it].Definition = "1"; - def_it++; - - defines[def_it].Name = "MSAA_SAMPLES"; - samples[0] = char(o.dx10_msaa_samples) + '0'; - samples[1] = 0; - defines[def_it].Definition = samples; - def_it++; - - static char def[256]; - if (m_MSAASample < 0) - def[0] = '0'; - else - def[0] = '0' + char(m_MSAASample); - - def[1] = 0; - defines[def_it].Name = "ISAMPLE"; - defines[def_it].Definition = def; - def_it++; - - - if (o.dx10_msaa_opt) - { - defines[def_it].Name = "MSAA_OPTIMIZATION"; - defines[def_it].Definition = "1"; - def_it++; - } - - sh_name[len] = '1'; - ++len; - sh_name[len] = '0' + char(o.dx10_msaa_samples); - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0' + char(o.dx10_msaa_opt); - ++len; - - switch (o.dx10_msaa_alphatest) - { - case MSAA_ATEST_DX10_0_ATOC: - defines[def_it].Name = "MSAA_ALPHATEST_DX10_0_ATOC"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - break; - case MSAA_ATEST_DX10_1_ATOC: - defines[def_it].Name = "MSAA_ALPHATEST_DX10_1_ATOC"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '0'; - ++len; - sh_name[len] = '1'; - ++len; - sh_name[len] = '0'; - ++len; - break; - case MSAA_ATEST_DX10_1_NATIVE: - defines[def_it].Name = "MSAA_ALPHATEST_DX10_1"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '1'; - ++len; - break; - default: - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - } - } - else - { - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - } - - // Compile sources list - size_t def_len = def_it * 5; - size_t sources_len = source.size() + def_len + 2; - string256 name_comment; - sprintf_s(name_comment, "// %s\n", name); - const char** sources = xr_alloc(sources_len); -#ifdef DEBUG - sources[0] = "#version 450\n#pragma optimize (off)\n"; -#else - sources[0] = "#version 450\n"; -#endif - sources[1] = name_comment; - memcpy(sources + 2, defines, def_len * sizeof(char*)); - memcpy(sources + def_len + 2, source.data(), source.size() * sizeof(char*)); - - // Compile the shader - GLuint shader = *(GLuint*)result; - R_ASSERT(shader); - CHK_GL(glShaderSource(shader, sources_len, sources, nullptr)); - CHK_GL(glCompileShader(shader)); - - // Create the shader program - GLuint program = glCreateProgram(); - R_ASSERT(program); - CHK_GL(glObjectLabel(GL_PROGRAM, program, -1, name)); - CHK_GL(glProgramParameteri(program, GL_PROGRAM_SEPARABLE, (GLint)GL_TRUE)); - *(GLuint*)result = program; - - // Free string resources - xr_free(sources); - for (xr_vector::iterator it = includes.begin(); it != includes.end(); ++it) - xr_free(*it); - - // Get the compilation result - GLint status; - CHK_GL(glGetShaderiv(shader, GL_COMPILE_STATUS, &status)); - - // Link program if compilation succeeded - GLchar* _pErrorMsgs = nullptr; - if ((GLboolean)status == GL_TRUE) - { - CHK_GL(glAttachShader(program, shader)); - CHK_GL(glBindFragDataLocation(program, 0, "SV_Target")); - CHK_GL(glBindFragDataLocation(program, 0, "SV_Target0")); - CHK_GL(glBindFragDataLocation(program, 1, "SV_Target1")); - CHK_GL(glBindFragDataLocation(program, 2, "SV_Target2")); - CHK_GL(glLinkProgram(program)); - CHK_GL(glDetachShader(program, shader)); - CHK_GL(glGetProgramiv(program, GL_LINK_STATUS, &status)); - - if ((GLboolean)status == GL_FALSE) - { - GLint length; - CHK_GL(glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length)); - _pErrorMsgs = xr_alloc(length); - CHK_GL(glGetProgramInfoLog(program, length, nullptr, _pErrorMsgs)); - } - } - else - { - GLint length; - CHK_GL(glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length)); - _pErrorMsgs = xr_alloc(length); - CHK_GL(glGetShaderInfoLog(shader, length, nullptr, _pErrorMsgs)); - } - - if ((GLboolean)status == GL_FALSE) - { -#ifdef DEBUG - GLint srcLen; - CHK_GL(glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &srcLen)); - GLchar* shaderSrc = xr_alloc(srcLen); - CHK_GL(glGetShaderSource(shader, srcLen, nullptr, shaderSrc)); -#endif - - Msg("! shader compilation failed"); - Log("! ", name); - if (_pErrorMsgs) - Log("! error: ", _pErrorMsgs); - -#ifdef DEBUG - if (shaderSrc) - { - Log("Shader source:"); - Log(shaderSrc); - Log("Shader source end."); - } - xr_free(shaderSrc); -#endif - - xr_free(_pErrorMsgs); - CHK_GL(glDeleteShader(shader)); - return E_FAIL; - } - - xr_free(_pErrorMsgs); - CHK_GL(glDeleteShader(shader)); - return S_OK; -} diff --git a/src/Layers/xrRenderPC_GL/rgl_shaders.cpp b/src/Layers/xrRenderPC_GL/rgl_shaders.cpp new file mode 100644 index 00000000000..9f0c95162c4 --- /dev/null +++ b/src/Layers/xrRenderPC_GL/rgl_shaders.cpp @@ -0,0 +1,660 @@ +#include "stdafx.h" +#include "rgl.h" + +void CRender::addShaderOption(const char* name, const char* value) +{ + m_ShaderOptions += "#define "; + m_ShaderOptions += name; + m_ShaderOptions += " "; + m_ShaderOptions += value; + m_ShaderOptions += "\n"; +} + +static inline bool match_shader_id( + LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result); + +///////// + +static inline void load_includes(LPCSTR pSrcData, UINT SrcDataLen, xr_vector& source, xr_vector& includes) +{ + // Copy source file data into a null-terminated buffer + char* srcData = xr_alloc(SrcDataLen + 2); + memcpy(srcData, pSrcData, SrcDataLen); + srcData[SrcDataLen] = '\n'; + srcData[SrcDataLen + 1] = '\0'; + includes.push_back(srcData); + source.push_back(srcData); + + string_path path; + char* str = srcData; + while (strstr(str, "#include") != nullptr) + { + // Get filename of include directive + str = strstr(str, "#include"); // Find the include directive + char* fn = strchr(str, '"') + 1; // Get filename, skip quotation + *str = '\0'; // Terminate previous source + str = strchr(fn, '"'); // Get end of filename path + *str = '\0'; // Terminate filename path + + // Create path to included shader + strconcat(sizeof path, path, GEnv.Render->getShaderPath(), fn); + FS.update_path(path, "$game_shaders$", path); + while (char* sep = strchr(path, '/')) + *sep = '\\'; + + // Open and read file, recursively load includes + IReader* R = FS.r_open(path); + R_ASSERT2(R, path); + load_includes((char*)R->pointer(), R->length(), source, includes); + FS.r_close(R); + + // Add next source, skip quotation + str++; + source.push_back(str); + } +} + +struct SHADER_MACRO +{ + char *Define = "#define ", *Name = "\n", *Sep = "\t", *Definition = "\n", *EOL = "\n"; +}; + +HRESULT CRender::shader_compile(LPCSTR name, DWORD const* pSrcData, UINT SrcDataLen, LPCSTR pFunctionName, + LPCSTR pTarget, DWORD Flags, void*& result) +{ + xr_vector source, includes; + SHADER_MACRO defines[128]; + int def_it = 0; + char c_smapsize[32]; + char c_gloss[32]; + char c_sun_shafts[32]; + char c_ssao[32]; + char c_sun_quality[32]; + + // TODO: OGL: Implement these parameters. + VERIFY(!pFunctionName); + VERIFY(!pTarget); + VERIFY(!Flags); + + // open included files + load_includes((LPCSTR)pSrcData, SrcDataLen, source, includes); + + char sh_name[MAX_PATH] = ""; + u32 len = 0; + // options + { + xr_sprintf(c_smapsize, "%04d", u32(o.smapsize)); + defines[def_it].Name = "SMAP_size"; + defines[def_it].Definition = c_smapsize; + def_it++; + VERIFY(xr_strlen(c_smapsize) == 4); + xr_strcat(sh_name, c_smapsize); + len += 4; + } + + if (o.fp16_filter) + { + defines[def_it].Name = "FP16_FILTER"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.fp16_filter); + ++len; + + if (o.fp16_blend) + { + defines[def_it].Name = "FP16_BLEND"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.fp16_blend); + ++len; + + if (o.HW_smap) + { + defines[def_it].Name = "USE_HWSMAP"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.HW_smap); + ++len; + + if (o.HW_smap_PCF) + { + defines[def_it].Name = "USE_HWSMAP_PCF"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.HW_smap_PCF); + ++len; + + if (o.HW_smap_FETCH4) + { + defines[def_it].Name = "USE_FETCH4"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.HW_smap_FETCH4); + ++len; + + if (o.sjitter) + { + defines[def_it].Name = "USE_SJITTER"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.sjitter); + ++len; + + if (HW.Caps.raster_major >= 3) + { + defines[def_it].Name = "USE_BRANCHING"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(HW.Caps.raster_major >= 3); + ++len; + + if (HW.Caps.geometry.bVTF) + { + defines[def_it].Name = "USE_VTF"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(HW.Caps.geometry.bVTF); + ++len; + + if (o.Tshadows) + { + defines[def_it].Name = "USE_TSHADOWS"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.Tshadows); + ++len; + + if (o.mblur) + { + defines[def_it].Name = "USE_MBLUR"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.mblur); + ++len; + + if (o.sunfilter) + { + defines[def_it].Name = "USE_SUNFILTER"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.sunfilter); + ++len; + + if (o.sunstatic) + { + defines[def_it].Name = "USE_R2_STATIC_SUN"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.sunstatic); + ++len; + + if (o.forcegloss) + { + xr_sprintf(c_gloss, "%f", o.forcegloss_v); + defines[def_it].Name = "FORCE_GLOSS"; + defines[def_it].Definition = c_gloss; + def_it++; + } + sh_name[len] = '0' + char(o.forcegloss); + ++len; + + if (o.forceskinw) + { + defines[def_it].Name = "SKIN_COLOR"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.forceskinw); + ++len; + + if (o.ssao_blur_on) + { + defines[def_it].Name = "USE_SSAO_BLUR"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.ssao_blur_on); + ++len; + + if (o.ssao_hdao) + { + defines[def_it].Name = "HDAO"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.ssao_hdao); + ++len; + + if (o.ssao_hbao) + { + defines[def_it].Name = "USE_HBAO"; + defines[def_it].Definition = "1"; + def_it++; + if (o.hbao_vectorized) + { + defines[def_it].Name = "VECTORIZED_CODE"; + defines[def_it].Definition = "1"; + def_it++; + } + } + sh_name[len] = '0' + char(o.ssao_hbao); + ++len; + sh_name[len] = '0' + char(o.ssao_hbao ? o.hbao_vectorized : 0); + ++len; + + if (o.ssao_opt_data) + { + defines[def_it].Name = "SSAO_OPT_DATA"; + if (o.ssao_half_data) + defines[def_it].Definition = "2"; + else + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.ssao_opt_data ? (o.ssao_half_data ? 2 : 1) : 0); + ++len; + + // skinning + if (m_skinning < 0) + { + defines[def_it].Name = "SKIN_NONE"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (0 == m_skinning) + { + defines[def_it].Name = "SKIN_0"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(0 == m_skinning); + ++len; + + if (1 == m_skinning) + { + defines[def_it].Name = "SKIN_1"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(1 == m_skinning); + ++len; + + if (2 == m_skinning) + { + defines[def_it].Name = "SKIN_2"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(2 == m_skinning); + ++len; + + if (3 == m_skinning) + { + defines[def_it].Name = "SKIN_3"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(3 == m_skinning); + ++len; + + if (4 == m_skinning) + { + defines[def_it].Name = "SKIN_4"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(4 == m_skinning); + ++len; + + // Igor: need restart options + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_WATER)) + { + defines[def_it].Name = "USE_SOFT_WATER"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_PARTICLES)) + { + defines[def_it].Name = "USE_SOFT_PARTICLES"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_DOF)) + { + defines[def_it].Name = "USE_DOF"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r_sun_shafts) + { + xr_sprintf(c_sun_shafts, "%d", ps_r_sun_shafts); + defines[def_it].Name = "SUN_SHAFTS_QUALITY"; + defines[def_it].Definition = c_sun_shafts; + def_it++; + sh_name[len] = '0' + char(ps_r_sun_shafts); + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r_ssao) + { + xr_sprintf(c_ssao, "%d", ps_r_ssao); + defines[def_it].Name = "SSAO_QUALITY"; + defines[def_it].Definition = c_ssao; + def_it++; + sh_name[len] = '0' + char(ps_r_ssao); + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r_sun_quality) + { + xr_sprintf(c_sun_quality, "%d", ps_r_sun_quality); + defines[def_it].Name = "SUN_QUALITY"; + defines[def_it].Definition = c_sun_quality; + def_it++; + sh_name[len] = '0' + char(ps_r_sun_quality); + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_STEEP_PARALLAX)) + { + defines[def_it].Name = "ALLOW_STEEPPARALLAX"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (o.dx10_gbuffer_opt) + { + defines[def_it].Name = "GBUFFER_OPTIMIZATION"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.dx10_gbuffer_opt); + ++len; + + if (o.dx10_sm4_1) + { + defines[def_it].Name = "SM_4_1"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.dx10_sm4_1); + ++len; + + if (o.dx10_minmax_sm) + { + defines[def_it].Name = "USE_MINMAX_SM"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.dx10_minmax_sm != 0); + ++len; + + // add a #define for DX10_1 MSAA support + if (o.dx10_msaa) + { + static char samples[2]; + + defines[def_it].Name = "USE_MSAA"; + defines[def_it].Definition = "1"; + def_it++; + + defines[def_it].Name = "MSAA_SAMPLES"; + samples[0] = char(o.dx10_msaa_samples) + '0'; + samples[1] = 0; + defines[def_it].Definition = samples; + def_it++; + + static char def[256]; + if (m_MSAASample < 0) + def[0] = '0'; + else + def[0] = '0' + char(m_MSAASample); + + def[1] = 0; + defines[def_it].Name = "ISAMPLE"; + defines[def_it].Definition = def; + def_it++; + + if (o.dx10_msaa_opt) + { + defines[def_it].Name = "MSAA_OPTIMIZATION"; + defines[def_it].Definition = "1"; + def_it++; + } + + sh_name[len] = '1'; + ++len; + sh_name[len] = '0' + char(o.dx10_msaa_samples); + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0' + char(o.dx10_msaa_opt); + ++len; + + switch (o.dx10_msaa_alphatest) + { + case MSAA_ATEST_DX10_0_ATOC: + defines[def_it].Name = "MSAA_ALPHATEST_DX10_0_ATOC"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + break; + case MSAA_ATEST_DX10_1_ATOC: + defines[def_it].Name = "MSAA_ALPHATEST_DX10_1_ATOC"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '0'; + ++len; + sh_name[len] = '1'; + ++len; + sh_name[len] = '0'; + ++len; + break; + case MSAA_ATEST_DX10_1_NATIVE: + defines[def_it].Name = "MSAA_ALPHATEST_DX10_1"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '1'; + ++len; + break; + default: + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + } + } + else + { + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + } + + // Compile sources list + size_t def_len = def_it * 5; + size_t sources_len = source.size() + def_len + 2; + string256 name_comment; + sprintf_s(name_comment, "// %s\n", name); + const char** sources = xr_alloc(sources_len); +#ifdef DEBUG + sources[0] = "#version 450\n#pragma optimize (off)\n"; +#else + sources[0] = "#version 450\n"; +#endif + sources[1] = name_comment; + memcpy(sources + 2, defines, def_len * sizeof(char*)); + memcpy(sources + def_len + 2, source.data(), source.size() * sizeof(char*)); + + // Compile the shader + GLuint shader = *(GLuint*)result; + R_ASSERT(shader); + CHK_GL(glShaderSource(shader, sources_len, sources, nullptr)); + CHK_GL(glCompileShader(shader)); + + // Create the shader program + GLuint program = glCreateProgram(); + R_ASSERT(program); + CHK_GL(glObjectLabel(GL_PROGRAM, program, -1, name)); + CHK_GL(glProgramParameteri(program, GL_PROGRAM_SEPARABLE, (GLint)GL_TRUE)); + *(GLuint*)result = program; + + // Free string resources + xr_free(sources); + for (xr_vector::iterator it = includes.begin(); it != includes.end(); ++it) + xr_free(*it); + + // Get the compilation result + GLint status; + CHK_GL(glGetShaderiv(shader, GL_COMPILE_STATUS, &status)); + + // Link program if compilation succeeded + GLchar* _pErrorMsgs = nullptr; + if ((GLboolean)status == GL_TRUE) + { + CHK_GL(glAttachShader(program, shader)); + CHK_GL(glBindFragDataLocation(program, 0, "SV_Target")); + CHK_GL(glBindFragDataLocation(program, 0, "SV_Target0")); + CHK_GL(glBindFragDataLocation(program, 1, "SV_Target1")); + CHK_GL(glBindFragDataLocation(program, 2, "SV_Target2")); + CHK_GL(glLinkProgram(program)); + CHK_GL(glDetachShader(program, shader)); + CHK_GL(glGetProgramiv(program, GL_LINK_STATUS, &status)); + + if ((GLboolean)status == GL_FALSE) + { + GLint length; + CHK_GL(glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length)); + _pErrorMsgs = xr_alloc(length); + CHK_GL(glGetProgramInfoLog(program, length, nullptr, _pErrorMsgs)); + } + } + else + { + GLint length; + CHK_GL(glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length)); + _pErrorMsgs = xr_alloc(length); + CHK_GL(glGetShaderInfoLog(shader, length, nullptr, _pErrorMsgs)); + } + + if ((GLboolean)status == GL_FALSE) + { +#ifdef DEBUG + GLint srcLen; + CHK_GL(glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &srcLen)); + GLchar* shaderSrc = xr_alloc(srcLen); + CHK_GL(glGetShaderSource(shader, srcLen, nullptr, shaderSrc)); +#endif + + Msg("! shader compilation failed"); + Log("! ", name); + if (_pErrorMsgs) + Log("! error: ", _pErrorMsgs); + +#ifdef DEBUG + if (shaderSrc) + { + Log("Shader source:"); + Log(shaderSrc); + Log("Shader source end."); + } + xr_free(shaderSrc); +#endif + + xr_free(_pErrorMsgs); + CHK_GL(glDeleteShader(shader)); + return E_FAIL; + } + + xr_free(_pErrorMsgs); + CHK_GL(glDeleteShader(shader)); + return S_OK; +} diff --git a/src/Layers/xrRenderPC_GL/xrRender_GL.vcxproj b/src/Layers/xrRenderPC_GL/xrRender_GL.vcxproj index c3d33906f5a..90f1a316255 100644 --- a/src/Layers/xrRenderPC_GL/xrRender_GL.vcxproj +++ b/src/Layers/xrRenderPC_GL/xrRender_GL.vcxproj @@ -310,6 +310,7 @@ + Create diff --git a/src/Layers/xrRenderPC_GL/xrRender_GL.vcxproj.filters b/src/Layers/xrRenderPC_GL/xrRender_GL.vcxproj.filters index 7ce248277c7..7e4a35f6fdd 100644 --- a/src/Layers/xrRenderPC_GL/xrRender_GL.vcxproj.filters +++ b/src/Layers/xrRenderPC_GL/xrRender_GL.vcxproj.filters @@ -675,6 +675,9 @@ Core_Target + + Core + diff --git a/src/Layers/xrRenderPC_R1/FStaticRender.cpp b/src/Layers/xrRenderPC_R1/FStaticRender.cpp index af2aa2fe617..76aef9ab85f 100644 --- a/src/Layers/xrRenderPC_R1/FStaticRender.cpp +++ b/src/Layers/xrRenderPC_R1/FStaticRender.cpp @@ -758,319 +758,3 @@ void CRender::DumpStatistics(IGameFont& font, IPerformanceAlert* alert) HOM.DumpStatistics(font, alert); Sectors_xrc.DumpStatistics(font, alert); } - -template -static HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, - T*& result, bool const disasm) -{ - result->sh = ShaderTypeTraits::CreateHWShader(buffer, buffer_size); - - LPCVOID data = nullptr; - - HRESULT const _hr = D3DXFindShaderComment(buffer, MAKEFOURCC('C', 'T', 'A', 'B'), &data, nullptr); - - if (SUCCEEDED(_hr) && data) - { - // Parse constant table data - LPD3DXSHADER_CONSTANTTABLE pConstants = LPD3DXSHADER_CONSTANTTABLE(data); - result->constants.parse(pConstants, ShaderTypeTraits::GetShaderDest()); - } - else - Msg("! D3DXFindShaderComment %s hr == 0x%08x", file_name, _hr); - - if (disasm) - { - ID3DXBuffer* disasm = nullptr; - D3DXDisassembleShader(LPDWORD(buffer), FALSE, nullptr, &disasm); - string_path dname; - strconcat(sizeof(dname), dname, "disasm\\", file_name, ('v' == pTarget[0]) ? ".vs" : ".ps"); - IWriter* W = FS.w_open("$logs$", dname); - W->w(disasm->GetBufferPointer(), disasm->GetBufferSize()); - FS.w_close(W); - _RELEASE(disasm); - } - - return _hr; -} - -inline HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, void*& result, bool const disasm) -{ - if (pTarget[0] == 'p') - return create_shader(pTarget, buffer, buffer_size, file_name, (SPS*&)result, disasm); - - if (pTarget[0] == 'v') - return create_shader(pTarget, buffer, buffer_size, file_name, (SVS*&)result, disasm); - - NODEFAULT; - return E_FAIL; -} - -class includer : public ID3DXInclude -{ -public: - HRESULT __stdcall Open( - D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) - { - string_path pname; - strconcat(sizeof(pname), pname, GEnv.Render->getShaderPath(), pFileName); - IReader* R = FS.r_open("$game_shaders$", pname); - if (nullptr == R) - { - // possibly in shared directory or somewhere else - open directly - R = FS.r_open("$game_shaders$", pFileName); - if (nullptr == R) - return E_FAIL; - } - - // duplicate and zero-terminate - u32 size = R->length(); - u8* data = xr_alloc(size + 1); - CopyMemory(data, R->pointer(), size); - data[size] = 0; - FS.r_close(R); - - *ppData = data; - *pBytes = size; - return D3D_OK; - } - HRESULT __stdcall Close(LPCVOID pData) - { - xr_free(pData); - return D3D_OK; - } -}; - -static inline bool match_shader_id( - LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result); - -HRESULT CRender::shader_compile(LPCSTR name, DWORD const* pSrcData, UINT SrcDataLen, LPCSTR pFunctionName, - LPCSTR pTarget, DWORD Flags, void*& result) -{ - D3DXMACRO defines[128]; - int def_it = 0; - - char sh_name[MAX_PATH] = ""; - u32 len = 0; - // options - if (o.forceskinw) - { - defines[def_it].Name = "SKIN_COLOR"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.forceskinw); - ++len; - - // skinning - if (m_skinning < 0) - { - defines[def_it].Name = "SKIN_NONE"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (0 == m_skinning) - { - defines[def_it].Name = "SKIN_0"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(0 == m_skinning); - ++len; - - if (1 == m_skinning) - { - defines[def_it].Name = "SKIN_1"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(1 == m_skinning); - ++len; - - if (2 == m_skinning) - { - defines[def_it].Name = "SKIN_2"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(2 == m_skinning); - ++len; - - if (3 == m_skinning) - { - defines[def_it].Name = "SKIN_3"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(3 == m_skinning); - ++len; - - if (4 == m_skinning) - { - defines[def_it].Name = "SKIN_4"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(4 == m_skinning); - ++len; - - sh_name[len] = '\0'; - - // finish - defines[def_it].Name = nullptr; - defines[def_it].Definition = nullptr; - def_it++; - R_ASSERT(def_it < 128); - - HRESULT _result = E_FAIL; - - string_path folder_name, folder; - xr_strcpy(folder, "r1\\objects\\r1\\"); - xr_strcat(folder, name); - xr_strcat(folder, "."); - - char extension[3]; - strncpy_s(extension, pTarget, 2); - xr_strcat(folder, extension); - - FS.update_path(folder_name, "$game_shaders$", folder); - xr_strcat(folder_name, "\\"); - - m_file_set.clear(); - FS.file_list(m_file_set, folder_name, FS_ListFiles | FS_RootOnly, "*"); - - string_path temp_file_name, file_name; - if (!match_shader_id(name, sh_name, m_file_set, temp_file_name)) - { - string_path file; - xr_strcpy(file, "shaders_cache\\r1\\"); - xr_strcat(file, name); - xr_strcat(file, "."); - xr_strcat(file, extension); - xr_strcat(file, "\\"); - xr_strcat(file, sh_name); - FS.update_path(file_name, "$app_data_root$", file); - } - else - { - xr_strcpy(file_name, folder_name); - xr_strcat(file_name, temp_file_name); - } - - if (FS.exist(file_name)) - { - IReader* file = FS.r_open(file_name); - if (file->length() > 4) - { - u32 crc = file->r_u32(); - u32 crcComp = crc32(file->pointer(), file->elapsed()); - if (crcComp == crc) - _result = create_shader(pTarget, (DWORD*)file->pointer(), file->elapsed(), file_name, result, o.disasm); - } - file->close(); - } - - if (FAILED(_result)) - { - includer Includer; - LPD3DXBUFFER pShaderBuf = nullptr; - LPD3DXBUFFER pErrorBuf = nullptr; - LPD3DXCONSTANTTABLE pConstants = nullptr; - LPD3DXINCLUDE pInclude = (LPD3DXINCLUDE)&Includer; - - _result = D3DXCompileShader((LPCSTR)pSrcData, SrcDataLen, defines, pInclude, pFunctionName, pTarget, - Flags | D3DXSHADER_USE_LEGACY_D3DX9_31_DLL, &pShaderBuf, &pErrorBuf, &pConstants); - if (SUCCEEDED(_result)) - { - IWriter* file = FS.w_open(file_name); - u32 crc = crc32(pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize()); - file->w_u32(crc); - file->w(pShaderBuf->GetBufferPointer(), (u32)pShaderBuf->GetBufferSize()); - FS.w_close(file); - - _result = create_shader(pTarget, (DWORD*)pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize(), - file_name, result, o.disasm); - } - else - { - Log("! ", file_name); - if (pErrorBuf) - Log("! error: ", (LPCSTR)pErrorBuf->GetBufferPointer()); - else - Msg("Can't compile shader hr=0x%08x", _result); - } - } - - return _result; -} - -static inline bool match_shader( - LPCSTR const debug_shader_id, LPCSTR const full_shader_id, LPCSTR const mask, size_t const mask_length) -{ - u32 const full_shader_id_length = xr_strlen(full_shader_id); - R_ASSERT2(full_shader_id_length == mask_length, - make_string("bad cache for shader %s, [%s], [%s]", debug_shader_id, mask, full_shader_id)); - char const* i = full_shader_id; - char const* const e = full_shader_id + full_shader_id_length; - char const* j = mask; - for (; i != e; ++i, ++j) - { - if (*i == *j) - continue; - - if (*j == '_') - continue; - - return false; - } - - return true; -} - -static inline bool match_shader_id( - LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result) -{ -#if 1 - strcpy_s ( result, "" ); - return false; -#else // #if 1 -#ifdef DEBUG - LPCSTR temp = ""; - bool found = false; - FS_FileSet::const_iterator i = file_set.begin(); - FS_FileSet::const_iterator const e = file_set.end(); - for (; i != e; ++i) - { - if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) - { - VERIFY(!found); - found = true; - temp = (*i).name.c_str(); - } - } - - xr_strcpy(result, temp); - return found; -#else // #ifdef DEBUG - FS_FileSet::const_iterator i = file_set.begin(); - FS_FileSet::const_iterator const e = file_set.end(); - for (; i != e; ++i) - { - if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) - { - xr_strcpy(result, (*i).name.c_str()); - return true; - } - } - - return false; -#endif // #ifdef DEBUG -#endif // #if 1 -} diff --git a/src/Layers/xrRenderPC_R1/FStaticRender_Shaders.cpp b/src/Layers/xrRenderPC_R1/FStaticRender_Shaders.cpp new file mode 100644 index 00000000000..336dd22ff76 --- /dev/null +++ b/src/Layers/xrRenderPC_R1/FStaticRender_Shaders.cpp @@ -0,0 +1,323 @@ +#include "stdafx.h" +#include "FStaticRender.h" +#include "Layers/xrRender/ShaderResourceTraits.h" + +template +static HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, + T*& result, bool const disasm) +{ + result->sh = ShaderTypeTraits::CreateHWShader(buffer, buffer_size); + + LPCVOID data = nullptr; + + HRESULT const _hr = D3DXFindShaderComment(buffer, MAKEFOURCC('C', 'T', 'A', 'B'), &data, nullptr); + + if (SUCCEEDED(_hr) && data) + { + // Parse constant table data + LPD3DXSHADER_CONSTANTTABLE pConstants = LPD3DXSHADER_CONSTANTTABLE(data); + result->constants.parse(pConstants, ShaderTypeTraits::GetShaderDest()); + } + else + Msg("! D3DXFindShaderComment %s hr == 0x%08x", file_name, _hr); + + if (disasm) + { + ID3DXBuffer* disasm = nullptr; + D3DXDisassembleShader(LPDWORD(buffer), FALSE, nullptr, &disasm); + string_path dname; + strconcat(sizeof(dname), dname, "disasm\\", file_name, ('v' == pTarget[0]) ? ".vs" : ".ps"); + IWriter* W = FS.w_open("$logs$", dname); + W->w(disasm->GetBufferPointer(), disasm->GetBufferSize()); + FS.w_close(W); + _RELEASE(disasm); + } + + return _hr; +} + +inline HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, + void*& result, bool const disasm) +{ + if (pTarget[0] == 'p') + return create_shader(pTarget, buffer, buffer_size, file_name, (SPS*&)result, disasm); + + if (pTarget[0] == 'v') + return create_shader(pTarget, buffer, buffer_size, file_name, (SVS*&)result, disasm); + + NODEFAULT; + return E_FAIL; +} + + +class includer : public ID3DXInclude +{ +public: + HRESULT __stdcall Open( + D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) + { + string_path pname; + strconcat(sizeof(pname), pname, GEnv.Render->getShaderPath(), pFileName); + IReader* R = FS.r_open("$game_shaders$", pname); + if (nullptr == R) + { + // possibly in shared directory or somewhere else - open directly + R = FS.r_open("$game_shaders$", pFileName); + if (nullptr == R) + return E_FAIL; + } + + // duplicate and zero-terminate + u32 size = R->length(); + u8* data = xr_alloc(size + 1); + CopyMemory(data, R->pointer(), size); + data[size] = 0; + FS.r_close(R); + + *ppData = data; + *pBytes = size; + return D3D_OK; + } + HRESULT __stdcall Close(LPCVOID pData) + { + xr_free(pData); + return D3D_OK; + } +}; + +static inline bool match_shader_id( + LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result); + + +HRESULT CRender::shader_compile(LPCSTR name, DWORD const* pSrcData, UINT SrcDataLen, LPCSTR pFunctionName, + LPCSTR pTarget, DWORD Flags, void*& result) +{ + D3DXMACRO defines[128]; + int def_it = 0; + + char sh_name[MAX_PATH] = ""; + u32 len = 0; + // options + if (o.forceskinw) + { + defines[def_it].Name = "SKIN_COLOR"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.forceskinw); + ++len; + + // skinning + if (m_skinning < 0) + { + defines[def_it].Name = "SKIN_NONE"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (0 == m_skinning) + { + defines[def_it].Name = "SKIN_0"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(0 == m_skinning); + ++len; + + if (1 == m_skinning) + { + defines[def_it].Name = "SKIN_1"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(1 == m_skinning); + ++len; + + if (2 == m_skinning) + { + defines[def_it].Name = "SKIN_2"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(2 == m_skinning); + ++len; + + if (3 == m_skinning) + { + defines[def_it].Name = "SKIN_3"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(3 == m_skinning); + ++len; + + if (4 == m_skinning) + { + defines[def_it].Name = "SKIN_4"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(4 == m_skinning); + ++len; + + sh_name[len] = '\0'; + + // finish + defines[def_it].Name = nullptr; + defines[def_it].Definition = nullptr; + def_it++; + R_ASSERT(def_it < 128); + + HRESULT _result = E_FAIL; + + string_path folder_name, folder; + xr_strcpy(folder, "r1\\objects\\r1\\"); + xr_strcat(folder, name); + xr_strcat(folder, "."); + + char extension[3]; + strncpy_s(extension, pTarget, 2); + xr_strcat(folder, extension); + + FS.update_path(folder_name, "$game_shaders$", folder); + xr_strcat(folder_name, "\\"); + + m_file_set.clear(); + FS.file_list(m_file_set, folder_name, FS_ListFiles | FS_RootOnly, "*"); + + string_path temp_file_name, file_name; + if (!match_shader_id(name, sh_name, m_file_set, temp_file_name)) + { + string_path file; + xr_strcpy(file, "shaders_cache\\r1\\"); + xr_strcat(file, name); + xr_strcat(file, "."); + xr_strcat(file, extension); + xr_strcat(file, "\\"); + xr_strcat(file, sh_name); + FS.update_path(file_name, "$app_data_root$", file); + } + else + { + xr_strcpy(file_name, folder_name); + xr_strcat(file_name, temp_file_name); + } + + if (FS.exist(file_name)) + { + IReader* file = FS.r_open(file_name); + if (file->length() > 4) + { + u32 crc = file->r_u32(); + u32 crcComp = crc32(file->pointer(), file->elapsed()); + if (crcComp == crc) + _result = create_shader(pTarget, (DWORD*)file->pointer(), file->elapsed(), file_name, result, o.disasm); + } + file->close(); + } + + if (FAILED(_result)) + { + includer Includer; + LPD3DXBUFFER pShaderBuf = nullptr; + LPD3DXBUFFER pErrorBuf = nullptr; + LPD3DXCONSTANTTABLE pConstants = nullptr; + LPD3DXINCLUDE pInclude = (LPD3DXINCLUDE)&Includer; + + _result = D3DXCompileShader((LPCSTR)pSrcData, SrcDataLen, defines, pInclude, pFunctionName, pTarget, + Flags | D3DXSHADER_USE_LEGACY_D3DX9_31_DLL, &pShaderBuf, &pErrorBuf, &pConstants); + if (SUCCEEDED(_result)) + { + IWriter* file = FS.w_open(file_name); + u32 crc = crc32(pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize()); + file->w_u32(crc); + file->w(pShaderBuf->GetBufferPointer(), (u32)pShaderBuf->GetBufferSize()); + FS.w_close(file); + + _result = create_shader(pTarget, (DWORD*)pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize(), + file_name, result, o.disasm); + } + else + { + Log("! ", file_name); + if (pErrorBuf) + Log("! error: ", (LPCSTR)pErrorBuf->GetBufferPointer()); + else + Msg("Can't compile shader hr=0x%08x", _result); + } + } + + return _result; +} + + +static inline bool match_shader( + LPCSTR const debug_shader_id, LPCSTR const full_shader_id, LPCSTR const mask, size_t const mask_length) +{ + u32 const full_shader_id_length = xr_strlen(full_shader_id); + R_ASSERT2(full_shader_id_length == mask_length, + make_string("bad cache for shader %s, [%s], [%s]", debug_shader_id, mask, full_shader_id)); + char const* i = full_shader_id; + char const* const e = full_shader_id + full_shader_id_length; + char const* j = mask; + for (; i != e; ++i, ++j) + { + if (*i == *j) + continue; + + if (*j == '_') + continue; + + return false; + } + + return true; +} + +static inline bool match_shader_id( + LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result) +{ +#if 1 + strcpy_s(result, ""); + return false; +#else // #if 1 +#ifdef DEBUG + LPCSTR temp = ""; + bool found = false; + FS_FileSet::const_iterator i = file_set.begin(); + FS_FileSet::const_iterator const e = file_set.end(); + for (; i != e; ++i) + { + if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) + { + VERIFY(!found); + found = true; + temp = (*i).name.c_str(); + } + } + + xr_strcpy(result, temp); + return found; +#else // #ifdef DEBUG + FS_FileSet::const_iterator i = file_set.begin(); + FS_FileSet::const_iterator const e = file_set.end(); + for (; i != e; ++i) + { + if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) + { + xr_strcpy(result, (*i).name.c_str()); + return true; + } + } + + return false; +#endif // #ifdef DEBUG +#endif // #if 1 +} diff --git a/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj b/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj index 5de44912074..c99ed68d706 100644 --- a/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj +++ b/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj @@ -428,6 +428,7 @@ + diff --git a/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj.filters b/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj.filters index 9224934507f..a93200a802a 100644 --- a/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj.filters +++ b/src/Layers/xrRenderPC_R1/xrRender_R1.vcxproj.filters @@ -956,6 +956,9 @@ Models\Visuals + + Core + diff --git a/src/Layers/xrRenderPC_R2/r2.cpp b/src/Layers/xrRenderPC_R2/r2.cpp index ddffb502a55..415c36b2531 100644 --- a/src/Layers/xrRenderPC_R2/r2.cpp +++ b/src/Layers/xrRenderPC_R2/r2.cpp @@ -628,591 +628,3 @@ void CRender::DumpStatistics(IGameFont& font, IPerformanceAlert* alert) HOM.DumpStatistics(font, alert); Sectors_xrc.DumpStatistics(font, alert); } - -template -static HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, - T*& result, bool const disasm) -{ - result->sh = ShaderTypeTraits::CreateHWShader(buffer, buffer_size); - - LPCVOID data = nullptr; - - HRESULT const _hr = D3DXFindShaderComment(buffer, MAKEFOURCC('C', 'T', 'A', 'B'), &data, nullptr); - - if (SUCCEEDED(_hr) && data) - { - // Parse constant table data - LPD3DXSHADER_CONSTANTTABLE pConstants = LPD3DXSHADER_CONSTANTTABLE(data); - result->constants.parse(pConstants, ShaderTypeTraits::GetShaderDest()); - } - else - Msg("! D3DXFindShaderComment %s hr == 0x%08x", file_name, _hr); - - if (disasm) - { - ID3DXBuffer* disasm = nullptr; - D3DXDisassembleShader(LPDWORD(buffer), FALSE, nullptr, &disasm); - string_path dname; - strconcat(sizeof(dname), dname, "disasm\\", file_name, ('v' == pTarget[0]) ? ".vs" : ".ps"); - IWriter* W = FS.w_open("$logs$", dname); - W->w(disasm->GetBufferPointer(), disasm->GetBufferSize()); - FS.w_close(W); - _RELEASE(disasm); - } - - return _hr; -} - -inline HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, void*& result, bool const disasm) -{ - if (pTarget[0] == 'p') - return create_shader(pTarget, buffer, buffer_size, file_name, (SPS*&)result, disasm); - - if (pTarget[0] == 'v') - return create_shader(pTarget, buffer, buffer_size, file_name, (SVS*&)result, disasm); - - NODEFAULT; - return E_FAIL; -} - -class includer : public ID3DXInclude -{ -public: - HRESULT __stdcall Open( - D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) - { - string_path pname; - strconcat(sizeof(pname), pname, GEnv.Render->getShaderPath(), pFileName); - IReader* R = FS.r_open("$game_shaders$", pname); - if (nullptr == R) - { - // possibly in shared directory or somewhere else - open directly - R = FS.r_open("$game_shaders$", pFileName); - if (nullptr == R) - return E_FAIL; - } - - // duplicate and zero-terminate - u32 size = R->length(); - u8* data = xr_alloc(size + 1); - CopyMemory(data, R->pointer(), size); - data[size] = 0; - FS.r_close(R); - - *ppData = data; - *pBytes = size; - return D3D_OK; - } - HRESULT __stdcall Close(LPCVOID pData) - { - xr_free(pData); - return D3D_OK; - } -}; - -static inline bool match_shader_id( - LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result); - -HRESULT CRender::shader_compile(LPCSTR name, DWORD const* pSrcData, UINT SrcDataLen, LPCSTR pFunctionName, - LPCSTR pTarget, DWORD Flags, void*& result) -{ - D3DXMACRO defines[128]; - int def_it = 0; - char c_smapsize[32]; - char c_gloss[32]; - char c_sun_shafts[32]; - char c_ssao[32]; - char c_sun_quality[32]; - - char sh_name[MAX_PATH] = ""; - u32 len = 0; - // options - { - xr_sprintf(c_smapsize, "%04d", u32(o.smapsize)); - defines[def_it].Name = "SMAP_size"; - defines[def_it].Definition = c_smapsize; - def_it++; - VERIFY(xr_strlen(c_smapsize) == 4 || atoi(c_smapsize) < 16384); - xr_strcat(sh_name, c_smapsize); - len += 4; - } - - if (o.fp16_filter) - { - defines[def_it].Name = "FP16_FILTER"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.fp16_filter); - ++len; - - if (o.fp16_blend) - { - defines[def_it].Name = "FP16_BLEND"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.fp16_blend); - ++len; - - if (o.HW_smap) - { - defines[def_it].Name = "USE_HWSMAP"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.HW_smap); - ++len; - - if (o.HW_smap_PCF) - { - defines[def_it].Name = "USE_HWSMAP_PCF"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.HW_smap_PCF); - ++len; - - if (o.HW_smap_FETCH4) - { - defines[def_it].Name = "USE_FETCH4"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.HW_smap_FETCH4); - ++len; - - if (o.sjitter) - { - defines[def_it].Name = "USE_SJITTER"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.sjitter); - ++len; - - if (HW.Caps.raster_major >= 3) - { - defines[def_it].Name = "USE_BRANCHING"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(HW.Caps.raster_major >= 3); - ++len; - - if (HW.Caps.geometry.bVTF) - { - defines[def_it].Name = "USE_VTF"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(HW.Caps.geometry.bVTF); - ++len; - - if (o.Tshadows) - { - defines[def_it].Name = "USE_TSHADOWS"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.Tshadows); - ++len; - - if (o.mblur) - { - defines[def_it].Name = "USE_MBLUR"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.mblur); - ++len; - - if (o.sunfilter) - { - defines[def_it].Name = "USE_SUNFILTER"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.sunfilter); - ++len; - - if (o.sunstatic) - { - defines[def_it].Name = "USE_R2_STATIC_SUN"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.sunstatic); - ++len; - - if (o.forcegloss) - { - xr_sprintf(c_gloss, "%f", o.forcegloss_v); - defines[def_it].Name = "FORCE_GLOSS"; - defines[def_it].Definition = c_gloss; - def_it++; - } - sh_name[len] = '0' + char(o.forcegloss); - ++len; - - if (o.forceskinw) - { - defines[def_it].Name = "SKIN_COLOR"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.forceskinw); - ++len; - - if (o.ssao_blur_on) - { - defines[def_it].Name = "USE_SSAO_BLUR"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.ssao_blur_on); - ++len; - - if (o.ssao_hbao) - { - defines[def_it].Name = "USE_HBAO"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.ssao_hbao); - ++len; - - if (o.ssao_opt_data) - { - defines[def_it].Name = "SSAO_OPT_DATA"; - if (o.ssao_half_data) - defines[def_it].Definition = "2"; - else - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.ssao_opt_data ? (o.ssao_half_data ? 2 : 1) : 0); - ++len; - - // skinning - if (m_skinning < 0) - { - defines[def_it].Name = "SKIN_NONE"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (0 == m_skinning) - { - defines[def_it].Name = "SKIN_0"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(0 == m_skinning); - ++len; - - if (1 == m_skinning) - { - defines[def_it].Name = "SKIN_1"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(1 == m_skinning); - ++len; - - if (2 == m_skinning) - { - defines[def_it].Name = "SKIN_2"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(2 == m_skinning); - ++len; - - if (3 == m_skinning) - { - defines[def_it].Name = "SKIN_3"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(3 == m_skinning); - ++len; - - if (4 == m_skinning) - { - defines[def_it].Name = "SKIN_4"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(4 == m_skinning); - ++len; - - // Igor: need restart options - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_WATER)) - { - defines[def_it].Name = "USE_SOFT_WATER"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_PARTICLES)) - { - defines[def_it].Name = "USE_SOFT_PARTICLES"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_DOF)) - { - defines[def_it].Name = "USE_DOF"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r_sun_shafts) - { - xr_sprintf(c_sun_shafts, "%d", ps_r_sun_shafts); - defines[def_it].Name = "SUN_SHAFTS_QUALITY"; - defines[def_it].Definition = c_sun_shafts; - def_it++; - sh_name[len] = '0' + char(ps_r_sun_shafts); - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r_ssao) - { - xr_sprintf(c_ssao, "%d", ps_r_ssao); - defines[def_it].Name = "SSAO_QUALITY"; - defines[def_it].Definition = c_ssao; - def_it++; - sh_name[len] = '0' + char(ps_r_ssao); - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r_sun_quality) - { - xr_sprintf(c_sun_quality, "%d", ps_r_sun_quality); - defines[def_it].Name = "SUN_QUALITY"; - defines[def_it].Definition = c_sun_quality; - def_it++; - sh_name[len] = '0' + char(ps_r_sun_quality); - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_STEEP_PARALLAX)) - { - defines[def_it].Name = "ALLOW_STEEPPARALLAX"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - sh_name[len] = '\0'; - - // finish - defines[def_it].Name = nullptr; - defines[def_it].Definition = nullptr; - def_it++; - - HRESULT _result = E_FAIL; - - string_path folder_name, folder; - xr_strcpy(folder, "r2\\objects\\r2\\"); - xr_strcat(folder, name); - xr_strcat(folder, "."); - - char extension[3]; - strncpy_s(extension, pTarget, 2); - xr_strcat(folder, extension); - - FS.update_path(folder_name, "$game_shaders$", folder); - xr_strcat(folder_name, "\\"); - - m_file_set.clear(); - FS.file_list(m_file_set, folder_name, FS_ListFiles | FS_RootOnly, "*"); - - string_path temp_file_name, file_name; - if (!match_shader_id(name, sh_name, m_file_set, temp_file_name)) - { - string_path file; - xr_strcpy(file, "shaders_cache\\r2\\"); - xr_strcat(file, name); - xr_strcat(file, "."); - xr_strcat(file, extension); - xr_strcat(file, "\\"); - xr_strcat(file, sh_name); - FS.update_path(file_name, "$app_data_root$", file); - } - else - { - xr_strcpy(file_name, folder_name); - xr_strcat(file_name, temp_file_name); - } - - if (FS.exist(file_name)) - { - IReader* file = FS.r_open(file_name); - if (file->length() > 4) - { - u32 crc = file->r_u32(); - u32 crcComp = crc32(file->pointer(), file->elapsed()); - if (crcComp == crc) - _result = create_shader(pTarget, (DWORD*)file->pointer(), file->elapsed(), file_name, result, o.disasm); - } - file->close(); - } - - if (FAILED(_result)) - { - if (0 == xr_strcmp(pFunctionName, "main")) - { - if ('v' == pTarget[0]) - pTarget = D3DXGetVertexShaderProfile(HW.pDevice); // vertex "vs_2_a"; - else - pTarget = D3DXGetPixelShaderProfile(HW.pDevice); // pixel "ps_2_a"; - } - - includer Includer; - LPD3DXBUFFER pShaderBuf = nullptr; - LPD3DXBUFFER pErrorBuf = nullptr; - LPD3DXCONSTANTTABLE pConstants = nullptr; - LPD3DXINCLUDE pInclude = (LPD3DXINCLUDE)&Includer; - - _result = D3DXCompileShader((LPCSTR)pSrcData, SrcDataLen, defines, pInclude, pFunctionName, pTarget, - Flags | D3DXSHADER_USE_LEGACY_D3DX9_31_DLL, &pShaderBuf, &pErrorBuf, &pConstants); - if (SUCCEEDED(_result)) - { - IWriter* file = FS.w_open(file_name); - u32 crc = crc32(pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize()); - file->w_u32(crc); - file->w(pShaderBuf->GetBufferPointer(), (u32)pShaderBuf->GetBufferSize()); - FS.w_close(file); - - _result = create_shader(pTarget, (DWORD*)pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize(), - file_name, result, o.disasm); - } - else - { - Log("! ", file_name); - if (pErrorBuf) - Log("! error: ", (LPCSTR)pErrorBuf->GetBufferPointer()); - else - Msg("Can't compile shader hr=0x%08x", _result); - } - } - - return _result; -} - -static inline bool match_shader( - LPCSTR const debug_shader_id, LPCSTR const full_shader_id, LPCSTR const mask, size_t const mask_length) -{ - u32 const full_shader_id_length = xr_strlen(full_shader_id); - R_ASSERT2(full_shader_id_length == mask_length, - make_string("bad cache for shader %s, [%s], [%s]", debug_shader_id, mask, full_shader_id)); - char const* i = full_shader_id; - char const* const e = full_shader_id + full_shader_id_length; - char const* j = mask; - for (; i != e; ++i, ++j) - { - if (*i == *j) - continue; - - if (*j == '_') - continue; - - return false; - } - - return true; -} - -static inline bool match_shader_id( - LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result) -{ -#if 1 - strcpy_s ( result, "" ); - return false; -#else // #if 1 -#ifdef DEBUG - LPCSTR temp = ""; - bool found = false; - FS_FileSet::const_iterator i = file_set.begin(); - FS_FileSet::const_iterator const e = file_set.end(); - for (; i != e; ++i) - { - if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) - { - VERIFY(!found); - found = true; - temp = (*i).name.c_str(); - } - } - - xr_strcpy(result, temp); - return found; -#else // #ifdef DEBUG - FS_FileSet::const_iterator i = file_set.begin(); - FS_FileSet::const_iterator const e = file_set.end(); - for (; i != e; ++i) - { - if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) - { - xr_strcpy(result, (*i).name.c_str()); - return true; - } - } - - return false; -#endif // #ifdef DEBUG -#endif // #if 1 -} diff --git a/src/Layers/xrRenderPC_R2/r2_shaders.cpp b/src/Layers/xrRenderPC_R2/r2_shaders.cpp new file mode 100644 index 00000000000..5ab560a7a32 --- /dev/null +++ b/src/Layers/xrRenderPC_R2/r2_shaders.cpp @@ -0,0 +1,592 @@ +#include "stdafx.h" +#include "r2.h" +#include "Layers/xrRender/ShaderResourceTraits.h" + +template +static HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, + T*& result, bool const disasm) +{ + result->sh = ShaderTypeTraits::CreateHWShader(buffer, buffer_size); + + LPCVOID data = nullptr; + + HRESULT const _hr = D3DXFindShaderComment(buffer, MAKEFOURCC('C', 'T', 'A', 'B'), &data, nullptr); + + if (SUCCEEDED(_hr) && data) + { + // Parse constant table data + LPD3DXSHADER_CONSTANTTABLE pConstants = LPD3DXSHADER_CONSTANTTABLE(data); + result->constants.parse(pConstants, ShaderTypeTraits::GetShaderDest()); + } + else + Msg("! D3DXFindShaderComment %s hr == 0x%08x", file_name, _hr); + + if (disasm) + { + ID3DXBuffer* disasm = nullptr; + D3DXDisassembleShader(LPDWORD(buffer), FALSE, nullptr, &disasm); + string_path dname; + strconcat(sizeof(dname), dname, "disasm\\", file_name, ('v' == pTarget[0]) ? ".vs" : ".ps"); + IWriter* W = FS.w_open("$logs$", dname); + W->w(disasm->GetBufferPointer(), disasm->GetBufferSize()); + FS.w_close(W); + _RELEASE(disasm); + } + + return _hr; +} + +inline HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, + void*& result, bool const disasm) +{ + if (pTarget[0] == 'p') + return create_shader(pTarget, buffer, buffer_size, file_name, (SPS*&)result, disasm); + + if (pTarget[0] == 'v') + return create_shader(pTarget, buffer, buffer_size, file_name, (SVS*&)result, disasm); + + NODEFAULT; + return E_FAIL; +} + +class includer : public ID3DXInclude +{ +public: + HRESULT __stdcall Open( + D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) + { + string_path pname; + strconcat(sizeof(pname), pname, GEnv.Render->getShaderPath(), pFileName); + IReader* R = FS.r_open("$game_shaders$", pname); + if (nullptr == R) + { + // possibly in shared directory or somewhere else - open directly + R = FS.r_open("$game_shaders$", pFileName); + if (nullptr == R) + return E_FAIL; + } + + // duplicate and zero-terminate + u32 size = R->length(); + u8* data = xr_alloc(size + 1); + CopyMemory(data, R->pointer(), size); + data[size] = 0; + FS.r_close(R); + + *ppData = data; + *pBytes = size; + return D3D_OK; + } + HRESULT __stdcall Close(LPCVOID pData) + { + xr_free(pData); + return D3D_OK; + } +}; + +static inline bool match_shader_id( + LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result); + +HRESULT CRender::shader_compile(LPCSTR name, DWORD const* pSrcData, UINT SrcDataLen, LPCSTR pFunctionName, + LPCSTR pTarget, DWORD Flags, void*& result) +{ + D3DXMACRO defines[128]; + int def_it = 0; + char c_smapsize[32]; + char c_gloss[32]; + char c_sun_shafts[32]; + char c_ssao[32]; + char c_sun_quality[32]; + + char sh_name[MAX_PATH] = ""; + u32 len = 0; + // options + { + xr_sprintf(c_smapsize, "%04d", u32(o.smapsize)); + defines[def_it].Name = "SMAP_size"; + defines[def_it].Definition = c_smapsize; + def_it++; + VERIFY(xr_strlen(c_smapsize) == 4 || atoi(c_smapsize) < 16384); + xr_strcat(sh_name, c_smapsize); + len += 4; + } + + if (o.fp16_filter) + { + defines[def_it].Name = "FP16_FILTER"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.fp16_filter); + ++len; + + if (o.fp16_blend) + { + defines[def_it].Name = "FP16_BLEND"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.fp16_blend); + ++len; + + if (o.HW_smap) + { + defines[def_it].Name = "USE_HWSMAP"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.HW_smap); + ++len; + + if (o.HW_smap_PCF) + { + defines[def_it].Name = "USE_HWSMAP_PCF"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.HW_smap_PCF); + ++len; + + if (o.HW_smap_FETCH4) + { + defines[def_it].Name = "USE_FETCH4"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.HW_smap_FETCH4); + ++len; + + if (o.sjitter) + { + defines[def_it].Name = "USE_SJITTER"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.sjitter); + ++len; + + if (HW.Caps.raster_major >= 3) + { + defines[def_it].Name = "USE_BRANCHING"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(HW.Caps.raster_major >= 3); + ++len; + + if (HW.Caps.geometry.bVTF) + { + defines[def_it].Name = "USE_VTF"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(HW.Caps.geometry.bVTF); + ++len; + + if (o.Tshadows) + { + defines[def_it].Name = "USE_TSHADOWS"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.Tshadows); + ++len; + + if (o.mblur) + { + defines[def_it].Name = "USE_MBLUR"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.mblur); + ++len; + + if (o.sunfilter) + { + defines[def_it].Name = "USE_SUNFILTER"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.sunfilter); + ++len; + + if (o.sunstatic) + { + defines[def_it].Name = "USE_R2_STATIC_SUN"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.sunstatic); + ++len; + + if (o.forcegloss) + { + xr_sprintf(c_gloss, "%f", o.forcegloss_v); + defines[def_it].Name = "FORCE_GLOSS"; + defines[def_it].Definition = c_gloss; + def_it++; + } + sh_name[len] = '0' + char(o.forcegloss); + ++len; + + if (o.forceskinw) + { + defines[def_it].Name = "SKIN_COLOR"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.forceskinw); + ++len; + + if (o.ssao_blur_on) + { + defines[def_it].Name = "USE_SSAO_BLUR"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.ssao_blur_on); + ++len; + + if (o.ssao_hbao) + { + defines[def_it].Name = "USE_HBAO"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.ssao_hbao); + ++len; + + if (o.ssao_opt_data) + { + defines[def_it].Name = "SSAO_OPT_DATA"; + if (o.ssao_half_data) + defines[def_it].Definition = "2"; + else + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.ssao_opt_data ? (o.ssao_half_data ? 2 : 1) : 0); + ++len; + + // skinning + if (m_skinning < 0) + { + defines[def_it].Name = "SKIN_NONE"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (0 == m_skinning) + { + defines[def_it].Name = "SKIN_0"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(0 == m_skinning); + ++len; + + if (1 == m_skinning) + { + defines[def_it].Name = "SKIN_1"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(1 == m_skinning); + ++len; + + if (2 == m_skinning) + { + defines[def_it].Name = "SKIN_2"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(2 == m_skinning); + ++len; + + if (3 == m_skinning) + { + defines[def_it].Name = "SKIN_3"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(3 == m_skinning); + ++len; + + if (4 == m_skinning) + { + defines[def_it].Name = "SKIN_4"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(4 == m_skinning); + ++len; + + // Igor: need restart options + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_WATER)) + { + defines[def_it].Name = "USE_SOFT_WATER"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_PARTICLES)) + { + defines[def_it].Name = "USE_SOFT_PARTICLES"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_DOF)) + { + defines[def_it].Name = "USE_DOF"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r_sun_shafts) + { + xr_sprintf(c_sun_shafts, "%d", ps_r_sun_shafts); + defines[def_it].Name = "SUN_SHAFTS_QUALITY"; + defines[def_it].Definition = c_sun_shafts; + def_it++; + sh_name[len] = '0' + char(ps_r_sun_shafts); + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r_ssao) + { + xr_sprintf(c_ssao, "%d", ps_r_ssao); + defines[def_it].Name = "SSAO_QUALITY"; + defines[def_it].Definition = c_ssao; + def_it++; + sh_name[len] = '0' + char(ps_r_ssao); + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r_sun_quality) + { + xr_sprintf(c_sun_quality, "%d", ps_r_sun_quality); + defines[def_it].Name = "SUN_QUALITY"; + defines[def_it].Definition = c_sun_quality; + def_it++; + sh_name[len] = '0' + char(ps_r_sun_quality); + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_STEEP_PARALLAX)) + { + defines[def_it].Name = "ALLOW_STEEPPARALLAX"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + sh_name[len] = '\0'; + + // finish + defines[def_it].Name = nullptr; + defines[def_it].Definition = nullptr; + def_it++; + + HRESULT _result = E_FAIL; + + string_path folder_name, folder; + xr_strcpy(folder, "r2\\objects\\r2\\"); + xr_strcat(folder, name); + xr_strcat(folder, "."); + + char extension[3]; + strncpy_s(extension, pTarget, 2); + xr_strcat(folder, extension); + + FS.update_path(folder_name, "$game_shaders$", folder); + xr_strcat(folder_name, "\\"); + + m_file_set.clear(); + FS.file_list(m_file_set, folder_name, FS_ListFiles | FS_RootOnly, "*"); + + string_path temp_file_name, file_name; + if (!match_shader_id(name, sh_name, m_file_set, temp_file_name)) + { + string_path file; + xr_strcpy(file, "shaders_cache\\r2\\"); + xr_strcat(file, name); + xr_strcat(file, "."); + xr_strcat(file, extension); + xr_strcat(file, "\\"); + xr_strcat(file, sh_name); + FS.update_path(file_name, "$app_data_root$", file); + } + else + { + xr_strcpy(file_name, folder_name); + xr_strcat(file_name, temp_file_name); + } + + if (FS.exist(file_name)) + { + IReader* file = FS.r_open(file_name); + if (file->length() > 4) + { + u32 crc = file->r_u32(); + u32 crcComp = crc32(file->pointer(), file->elapsed()); + if (crcComp == crc) + _result = create_shader(pTarget, (DWORD*)file->pointer(), file->elapsed(), file_name, result, o.disasm); + } + file->close(); + } + + if (FAILED(_result)) + { + if (0 == xr_strcmp(pFunctionName, "main")) + { + if ('v' == pTarget[0]) + pTarget = D3DXGetVertexShaderProfile(HW.pDevice); // vertex "vs_2_a"; + else + pTarget = D3DXGetPixelShaderProfile(HW.pDevice); // pixel "ps_2_a"; + } + + includer Includer; + LPD3DXBUFFER pShaderBuf = nullptr; + LPD3DXBUFFER pErrorBuf = nullptr; + LPD3DXCONSTANTTABLE pConstants = nullptr; + LPD3DXINCLUDE pInclude = (LPD3DXINCLUDE)&Includer; + + _result = D3DXCompileShader((LPCSTR)pSrcData, SrcDataLen, defines, pInclude, pFunctionName, pTarget, + Flags | D3DXSHADER_USE_LEGACY_D3DX9_31_DLL, &pShaderBuf, &pErrorBuf, &pConstants); + if (SUCCEEDED(_result)) + { + IWriter* file = FS.w_open(file_name); + u32 crc = crc32(pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize()); + file->w_u32(crc); + file->w(pShaderBuf->GetBufferPointer(), (u32)pShaderBuf->GetBufferSize()); + FS.w_close(file); + + _result = create_shader(pTarget, (DWORD*)pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize(), + file_name, result, o.disasm); + } + else + { + Log("! ", file_name); + if (pErrorBuf) + Log("! error: ", (LPCSTR)pErrorBuf->GetBufferPointer()); + else + Msg("Can't compile shader hr=0x%08x", _result); + } + } + + return _result; +} + +static inline bool match_shader( + LPCSTR const debug_shader_id, LPCSTR const full_shader_id, LPCSTR const mask, size_t const mask_length) +{ + u32 const full_shader_id_length = xr_strlen(full_shader_id); + R_ASSERT2(full_shader_id_length == mask_length, + make_string("bad cache for shader %s, [%s], [%s]", debug_shader_id, mask, full_shader_id)); + char const* i = full_shader_id; + char const* const e = full_shader_id + full_shader_id_length; + char const* j = mask; + for (; i != e; ++i, ++j) + { + if (*i == *j) + continue; + + if (*j == '_') + continue; + + return false; + } + + return true; +} + +static inline bool match_shader_id( + LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result) +{ +#if 1 + strcpy_s(result, ""); + return false; +#else // #if 1 +#ifdef DEBUG + LPCSTR temp = ""; + bool found = false; + FS_FileSet::const_iterator i = file_set.begin(); + FS_FileSet::const_iterator const e = file_set.end(); + for (; i != e; ++i) + { + if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) + { + VERIFY(!found); + found = true; + temp = (*i).name.c_str(); + } + } + + xr_strcpy(result, temp); + return found; +#else // #ifdef DEBUG + FS_FileSet::const_iterator i = file_set.begin(); + FS_FileSet::const_iterator const e = file_set.end(); + for (; i != e; ++i) + { + if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) + { + xr_strcpy(result, (*i).name.c_str()); + return true; + } + } + + return false; +#endif // #ifdef DEBUG +#endif // #if 1 +} diff --git a/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj b/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj index ce50db0dd2c..2dc727db8bb 100644 --- a/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj +++ b/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj @@ -478,6 +478,7 @@ + Create diff --git a/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj.filters b/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj.filters index e2532efaeb3..1b3cb090c1b 100644 --- a/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj.filters +++ b/src/Layers/xrRenderPC_R2/xrRender_R2.vcxproj.filters @@ -1100,6 +1100,9 @@ Shading templates + + Core + diff --git a/src/Layers/xrRenderPC_R3/r3.cpp b/src/Layers/xrRenderPC_R3/r3.cpp index cc4baeb46db..efb1d0e24df 100644 --- a/src/Layers/xrRenderPC_R3/r3.cpp +++ b/src/Layers/xrRenderPC_R3/r3.cpp @@ -759,828 +759,3 @@ void CRender::DumpStatistics(IGameFont& font, IPerformanceAlert* alert) HOM.DumpStatistics(font, alert); Sectors_xrc.DumpStatistics(font, alert); } - -template -static HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, - T*& result, bool const disasm) -{ - // XXX: disasm it - - result->sh = ShaderTypeTraits::CreateHWShader(buffer, buffer_size); - - ID3DShaderReflection* pReflection = 0; - -#ifdef USE_DX11 - HRESULT const _hr = D3DReflect(buffer, buffer_size, IID_ID3DShaderReflection, (void**)&pReflection); -#else - HRESULT const _hr = D3D10ReflectShader(buffer, buffer_size, &pReflection); -#endif - - if (SUCCEEDED(_hr) && pReflection) - { - // Parse constant table data - result->constants.parse(pReflection, ShaderTypeTraits::GetShaderDest()); - - _RELEASE(pReflection); - } - else - { - Msg("! D3DReflectShader %s hr == 0x%08x", file_name, _hr); - } - - return _hr; -} - -static HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, void*& result, bool const disasm) -{ - // XXX: what's going on with casts here??? - HRESULT _result = E_FAIL; - if (pTarget[0] == 'p') - { - _result = create_shader(pTarget, buffer, buffer_size, file_name, (SPS*&)result, disasm); - } - else if (pTarget[0] == 'v') - { - // XXX: try to use code below - // _result = create_shader(pTarget, buffer, buffer_size, file_name, (SVS*&)result, disasm); - - SVS* svs_result = (SVS*)result; -#ifdef USE_DX11 - _result = HW.pDevice->CreateVertexShader(buffer, buffer_size, 0, &svs_result->sh); -#else // #ifdef USE_DX11 - _result = HW.pDevice->CreateVertexShader(buffer, buffer_size, &svs_result->sh); -#endif // #ifdef USE_DX11 - - if (!SUCCEEDED(_result)) - { - Log("! VS: ", file_name); - Msg("! CreatePixelShader hr == 0x%08x", _result); - return E_FAIL; - } - - ID3DShaderReflection* pReflection = 0; -#ifdef USE_DX11 - _result = D3DReflect(buffer, buffer_size, IID_ID3DShaderReflection, (void**)&pReflection); -#else - _result = D3D10ReflectShader(buffer, buffer_size, &pReflection); -#endif - - // Parse constant, texture, sampler binding - // Store input signature blob - if (SUCCEEDED(_result) && pReflection) - { - // TODO: DX10: share the same input signatures - - // Store input signature (need only for VS) - // CHK_DX( D3DxxGetInputSignatureBlob(pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize(), - // &_vs->signature) ); - ID3DBlob* pSignatureBlob; - CHK_DX(D3DGetInputSignatureBlob(buffer, buffer_size, &pSignatureBlob)); - VERIFY(pSignatureBlob); - - svs_result->signature = RImplementation.Resources->_CreateInputSignature(pSignatureBlob); - - _RELEASE(pSignatureBlob); - - // Let constant table parse it's data - svs_result->constants.parse(pReflection, RC_dest_vertex); - - _RELEASE(pReflection); - } - else - { - Log("! VS: ", file_name); - Msg("! D3DXFindShaderComment hr == 0x%08x", _result); - } - } - else if (pTarget[0] == 'g') - { - _result = create_shader(pTarget, buffer, buffer_size, file_name, (SGS*&)result, disasm); - } - else - { - NODEFAULT; - } - - if (disasm) - { - ID3DBlob* disasm = 0; - D3DDisassemble(buffer, buffer_size, FALSE, 0, &disasm); - // D3DXDisassembleShader (LPDWORD(code->GetBufferPointer()), FALSE, 0, &disasm ); - string_path dname; - strconcat(sizeof(dname), dname, "disasm\\", file_name, - ('v' == pTarget[0]) ? ".vs" : ('p' == pTarget[0]) ? ".ps" : ".gs"); - IWriter* W = FS.w_open("$logs$", dname); - W->w(disasm->GetBufferPointer(), (u32)disasm->GetBufferSize()); - FS.w_close(W); - _RELEASE(disasm); - } - - return _result; -} - -class includer : public ID3DInclude -{ -public: - HRESULT __stdcall Open( - D3D10_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) - { - string_path pname; - strconcat(sizeof(pname), pname, GEnv.Render->getShaderPath(), pFileName); - IReader* R = FS.r_open("$game_shaders$", pname); - if (nullptr == R) - { - // possibly in shared directory or somewhere else - open directly - R = FS.r_open("$game_shaders$", pFileName); - if (nullptr == R) - return E_FAIL; - } - - // duplicate and zero-terminate - u32 size = R->length(); - u8* data = xr_alloc(size + 1); - CopyMemory(data, R->pointer(), size); - data[size] = 0; - FS.r_close(R); - - *ppData = data; - *pBytes = size; - return D3D_OK; - } - HRESULT __stdcall Close(LPCVOID pData) - { - xr_free(pData); - return D3D_OK; - } -}; - -static inline bool match_shader_id( - LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result); - -HRESULT CRender::shader_compile(LPCSTR name, DWORD const* pSrcData, UINT SrcDataLen, LPCSTR pFunctionName, - LPCSTR pTarget, DWORD Flags, void*& result) -{ - D3D_SHADER_MACRO defines[128]; - int def_it = 0; - char c_smapsize[32]; - char c_gloss[32]; - char c_sun_shafts[32]; - char c_ssao[32]; - char c_sun_quality[32]; - - char sh_name[MAX_PATH] = ""; - u32 len = 0; - // options - { - xr_sprintf(c_smapsize, "%04d", u32(o.smapsize)); - defines[def_it].Name = "SMAP_size"; - defines[def_it].Definition = c_smapsize; - def_it++; - VERIFY(xr_strlen(c_smapsize) == 4 || atoi(c_smapsize) < 16384); - xr_strcat(sh_name, c_smapsize); - len += 4; - } - - if (o.fp16_filter) - { - defines[def_it].Name = "FP16_FILTER"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.fp16_filter); - ++len; - - if (o.fp16_blend) - { - defines[def_it].Name = "FP16_BLEND"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.fp16_blend); - ++len; - - if (o.HW_smap) - { - defines[def_it].Name = "USE_HWSMAP"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.HW_smap); - ++len; - - if (o.HW_smap_PCF) - { - defines[def_it].Name = "USE_HWSMAP_PCF"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.HW_smap_PCF); - ++len; - - if (o.HW_smap_FETCH4) - { - defines[def_it].Name = "USE_FETCH4"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.HW_smap_FETCH4); - ++len; - - if (o.sjitter) - { - defines[def_it].Name = "USE_SJITTER"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.sjitter); - ++len; - - if (HW.Caps.raster_major >= 3) - { - defines[def_it].Name = "USE_BRANCHING"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(HW.Caps.raster_major >= 3); - ++len; - - if (HW.Caps.geometry.bVTF) - { - defines[def_it].Name = "USE_VTF"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(HW.Caps.geometry.bVTF); - ++len; - - if (o.Tshadows) - { - defines[def_it].Name = "USE_TSHADOWS"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.Tshadows); - ++len; - - if (o.mblur) - { - defines[def_it].Name = "USE_MBLUR"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.mblur); - ++len; - - if (o.sunfilter) - { - defines[def_it].Name = "USE_SUNFILTER"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.sunfilter); - ++len; - - if (o.sunstatic) - { - defines[def_it].Name = "USE_R2_STATIC_SUN"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.sunstatic); - ++len; - - if (o.forcegloss) - { - xr_sprintf(c_gloss, "%f", o.forcegloss_v); - defines[def_it].Name = "FORCE_GLOSS"; - defines[def_it].Definition = c_gloss; - def_it++; - } - sh_name[len] = '0' + char(o.forcegloss); - ++len; - - if (o.forceskinw) - { - defines[def_it].Name = "SKIN_COLOR"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.forceskinw); - ++len; - - if (o.ssao_blur_on) - { - defines[def_it].Name = "USE_SSAO_BLUR"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.ssao_blur_on); - ++len; - - if (o.ssao_hdao) - { - defines[def_it].Name = "HDAO"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.ssao_hdao); - ++len; - - if (o.ssao_hbao) - { - defines[def_it].Name = "USE_HBAO"; - defines[def_it].Definition = "1"; - def_it++; - if (o.hbao_vectorized) - { - defines[def_it].Name = "VECTORIZED_CODE"; - defines[def_it].Definition = "1"; - def_it++; - } - } - sh_name[len] = '0' + char(o.ssao_hbao); - ++len; - sh_name[len] = '0' + char(o.ssao_hbao ? o.hbao_vectorized : 0); - ++len; - - if (o.ssao_opt_data) - { - defines[def_it].Name = "SSAO_OPT_DATA"; - if (o.ssao_half_data) - defines[def_it].Definition = "2"; - else - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.ssao_opt_data ? (o.ssao_half_data ? 2 : 1) : 0); - ++len; - - // skinning - if (m_skinning < 0) - { - defines[def_it].Name = "SKIN_NONE"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (0 == m_skinning) - { - defines[def_it].Name = "SKIN_0"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(0 == m_skinning); - ++len; - - if (1 == m_skinning) - { - defines[def_it].Name = "SKIN_1"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(1 == m_skinning); - ++len; - - if (2 == m_skinning) - { - defines[def_it].Name = "SKIN_2"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(2 == m_skinning); - ++len; - - if (3 == m_skinning) - { - defines[def_it].Name = "SKIN_3"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(3 == m_skinning); - ++len; - - if (4 == m_skinning) - { - defines[def_it].Name = "SKIN_4"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(4 == m_skinning); - ++len; - - // Igor: need restart options - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_WATER)) - { - defines[def_it].Name = "USE_SOFT_WATER"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_PARTICLES)) - { - defines[def_it].Name = "USE_SOFT_PARTICLES"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_DOF)) - { - defines[def_it].Name = "USE_DOF"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r_sun_shafts) - { - xr_sprintf(c_sun_shafts, "%d", ps_r_sun_shafts); - defines[def_it].Name = "SUN_SHAFTS_QUALITY"; - defines[def_it].Definition = c_sun_shafts; - def_it++; - sh_name[len] = '0' + char(ps_r_sun_shafts); - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r_ssao) - { - xr_sprintf(c_ssao, "%d", ps_r_ssao); - defines[def_it].Name = "SSAO_QUALITY"; - defines[def_it].Definition = c_ssao; - def_it++; - sh_name[len] = '0' + char(ps_r_ssao); - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r_sun_quality) - { - xr_sprintf(c_sun_quality, "%d", ps_r_sun_quality); - defines[def_it].Name = "SUN_QUALITY"; - defines[def_it].Definition = c_sun_quality; - def_it++; - sh_name[len] = '0' + char(ps_r_sun_quality); - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_STEEP_PARALLAX)) - { - defines[def_it].Name = "ALLOW_STEEPPARALLAX"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (o.dx10_gbuffer_opt) - { - defines[def_it].Name = "GBUFFER_OPTIMIZATION"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.dx10_gbuffer_opt); - ++len; - - if (o.dx10_sm4_1) - { - defines[def_it].Name = "SM_4_1"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.dx10_sm4_1); - ++len; - - if (o.dx10_minmax_sm) - { - defines[def_it].Name = "USE_MINMAX_SM"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.dx10_minmax_sm != 0); - ++len; - - // Be carefull!!!!! this should be at the end to correctly generate - // compiled shader name; - // add a #define for DX10_1 MSAA support - if (o.dx10_msaa) - { - defines[def_it].Name = "USE_MSAA"; - defines[def_it].Definition = "1"; - def_it++; - - static char samples[2]; - - defines[def_it].Name = "MSAA_SAMPLES"; - samples[0] = char(o.dx10_msaa_samples) + '0'; - samples[1] = 0; - defines[def_it].Definition = samples; - def_it++; - - static char def[256]; - if (m_MSAASample < 0) - def[0] = '0'; - else - def[0] = '0' + char(m_MSAASample); - - def[1] = 0; - defines[def_it].Name = "ISAMPLE"; - defines[def_it].Definition = def; - def_it++; - - if (o.dx10_msaa_opt) - { - defines[def_it].Name = "MSAA_OPTIMIZATION"; - defines[def_it].Definition = "1"; - def_it++; - } - - sh_name[len] = '1'; - ++len; - sh_name[len] = '0' + char(o.dx10_msaa_samples); - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0' + char(o.dx10_msaa_opt); - ++len; - - switch (o.dx10_msaa_alphatest) - { - case MSAA_ATEST_DX10_0_ATOC: - defines[def_it].Name = "MSAA_ALPHATEST_DX10_0_ATOC"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - break; - case MSAA_ATEST_DX10_1_ATOC: - defines[def_it].Name = "MSAA_ALPHATEST_DX10_1_ATOC"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '0'; - ++len; - sh_name[len] = '1'; - ++len; - sh_name[len] = '0'; - ++len; - break; - case MSAA_ATEST_DX10_1_NATIVE: - defines[def_it].Name = "MSAA_ALPHATEST_DX10_1"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '1'; - ++len; - break; - default: - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - } - } - else - { - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - } - - sh_name[len] = '\0'; - - // finish - defines[def_it].Name = nullptr; - defines[def_it].Definition = nullptr; - def_it++; - - if (0 == xr_strcmp(pFunctionName, "main")) - { - if ('v' == pTarget[0]) - { - if (HW.pDevice1 == 0) - pTarget = D3D10GetVertexShaderProfile(HW.pDevice); // vertex "vs_4_0"; - else - pTarget = "vs_4_1"; // pixel "ps_4_0"; - } - else if ('p' == pTarget[0]) - { - if (HW.pDevice1 == 0) - pTarget = D3D10GetPixelShaderProfile(HW.pDevice); // pixel "ps_4_0"; - else - pTarget = "ps_4_1"; // pixel "ps_4_0"; - } - else if ('g' == pTarget[0]) - { - if (HW.pDevice1 == 0) - pTarget = D3D10GetGeometryShaderProfile(HW.pDevice); // geometry "gs_4_0"; - else - pTarget = "gs_4_1"; // pixel "ps_4_0"; - } - } - - HRESULT _result = E_FAIL; - - string_path folder_name, folder; - xr_strcpy(folder, "r3\\objects\\r3\\"); - xr_strcat(folder, name); - xr_strcat(folder, "."); - - char extension[3]; - strncpy_s(extension, pTarget, 2); - xr_strcat(folder, extension); - - FS.update_path(folder_name, "$game_shaders$", folder); - xr_strcat(folder_name, "\\"); - - m_file_set.clear(); - FS.file_list(m_file_set, folder_name, FS_ListFiles | FS_RootOnly, "*"); - - string_path temp_file_name, file_name; - if (!match_shader_id(name, sh_name, m_file_set, temp_file_name)) - { - string_path file; - xr_strcpy(file, "shaders_cache\\r3\\"); - xr_strcat(file, name); - xr_strcat(file, "."); - xr_strcat(file, extension); - xr_strcat(file, "\\"); - xr_strcat(file, sh_name); - FS.update_path(file_name, "$app_data_root$", file); - } - else - { - xr_strcpy(file_name, folder_name); - xr_strcat(file_name, temp_file_name); - } - - if (FS.exist(file_name)) - { - IReader* file = FS.r_open(file_name); - if (file->length() > 4) - { - u32 crc = file->r_u32(); - u32 crcComp = crc32(file->pointer(), file->elapsed()); - if (crcComp == crc) - _result = create_shader(pTarget, (DWORD*)file->pointer(), file->elapsed(), file_name, result, o.disasm); - } - file->close(); - } - - if (FAILED(_result)) - { - includer Includer; - LPD3DBLOB pShaderBuf = NULL; - LPD3DBLOB pErrorBuf = NULL; - _result = D3DCompile(pSrcData, SrcDataLen, "", defines, &Includer, pFunctionName, pTarget, Flags, 0, &pShaderBuf, &pErrorBuf); - - if (SUCCEEDED(_result)) - { - IWriter* file = FS.w_open(file_name); - u32 crc = crc32(pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize()); - file->w_u32(crc); - file->w(pShaderBuf->GetBufferPointer(), (u32)pShaderBuf->GetBufferSize()); - FS.w_close(file); - - _result = create_shader(pTarget, (DWORD*)pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize(), - file_name, result, o.disasm); - } - else - { - Log("! ", file_name); - if (pErrorBuf) - Log("! error: ", (LPCSTR)pErrorBuf->GetBufferPointer()); - else - Msg("Can't compile shader hr=0x%08x", _result); - } - } - - return _result; -} - -static inline bool match_shader( - LPCSTR const debug_shader_id, LPCSTR const full_shader_id, LPCSTR const mask, size_t const mask_length) -{ - u32 const full_shader_id_length = xr_strlen(full_shader_id); - R_ASSERT2(full_shader_id_length == mask_length, - make_string("bad cache for shader %s, [%s], [%s]", debug_shader_id, mask, full_shader_id)); - char const* i = full_shader_id; - char const* const e = full_shader_id + full_shader_id_length; - char const* j = mask; - for (; i != e; ++i, ++j) - { - if (*i == *j) - continue; - - if (*j == '_') - continue; - - return false; - } - - return true; -} - -static inline bool match_shader_id( - LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result) -{ -#if 1 - strcpy_s ( result, "" ); - return false; -#else // #if 1 -#ifdef DEBUG - LPCSTR temp = ""; - bool found = false; - FS_FileSet::const_iterator i = file_set.begin(); - FS_FileSet::const_iterator const e = file_set.end(); - for (; i != e; ++i) - { - if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) - { - VERIFY(!found); - found = true; - temp = (*i).name.c_str(); - } - } - - xr_strcpy(result, temp); - return found; -#else // #ifdef DEBUG - FS_FileSet::const_iterator i = file_set.begin(); - FS_FileSet::const_iterator const e = file_set.end(); - for (; i != e; ++i) - { - if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) - { - xr_strcpy(result, (*i).name.c_str()); - return true; - } - } - - return false; -#endif // #ifdef DEBUG -#endif // #if 1 -} diff --git a/src/Layers/xrRenderPC_R3/r3_shaders.cpp b/src/Layers/xrRenderPC_R3/r3_shaders.cpp new file mode 100644 index 00000000000..2b7990682db --- /dev/null +++ b/src/Layers/xrRenderPC_R3/r3_shaders.cpp @@ -0,0 +1,817 @@ +#include "stdafx.h" +#include "r3.h" +#include "Layers/xrRender/ShaderResourceTraits.h" + +template +static HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, + T*& result, bool const disasm) +{ + // XXX: disasm it + + result->sh = ShaderTypeTraits::CreateHWShader(buffer, buffer_size); + + ID3DShaderReflection* pReflection = 0; + HRESULT const _hr = D3D10ReflectShader(buffer, buffer_size, &pReflection); + + if (SUCCEEDED(_hr) && pReflection) + { + // Parse constant table data + result->constants.parse(pReflection, ShaderTypeTraits::GetShaderDest()); + + _RELEASE(pReflection); + } + else + { + Msg("! D3DReflectShader %s hr == 0x%08x", file_name, _hr); + } + + return _hr; +} + +static HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, + void*& result, bool const disasm) +{ + // XXX: what's going on with casts here??? + HRESULT _result = E_FAIL; + if (pTarget[0] == 'p') + { + _result = create_shader(pTarget, buffer, buffer_size, file_name, (SPS*&)result, disasm); + } + else if (pTarget[0] == 'v') + { + // XXX: try to use code below + // _result = create_shader(pTarget, buffer, buffer_size, file_name, (SVS*&)result, disasm); + + SVS* svs_result = (SVS*)result; + _result = HW.pDevice->CreateVertexShader(buffer, buffer_size, &svs_result->sh); + + if (!SUCCEEDED(_result)) + { + Log("! VS: ", file_name); + Msg("! CreatePixelShader hr == 0x%08x", _result); + return E_FAIL; + } + + ID3DShaderReflection* pReflection = 0; + _result = D3D10ReflectShader(buffer, buffer_size, &pReflection); + + // Parse constant, texture, sampler binding + // Store input signature blob + if (SUCCEEDED(_result) && pReflection) + { + // TODO: DX10: share the same input signatures + + // Store input signature (need only for VS) + // CHK_DX( D3DxxGetInputSignatureBlob(pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize(), + // &_vs->signature) ); + ID3DBlob* pSignatureBlob; + CHK_DX(D3DGetInputSignatureBlob(buffer, buffer_size, &pSignatureBlob)); + VERIFY(pSignatureBlob); + + svs_result->signature = RImplementation.Resources->_CreateInputSignature(pSignatureBlob); + + _RELEASE(pSignatureBlob); + + // Let constant table parse it's data + svs_result->constants.parse(pReflection, RC_dest_vertex); + + _RELEASE(pReflection); + } + else + { + Log("! VS: ", file_name); + Msg("! D3DXFindShaderComment hr == 0x%08x", _result); + } + } + else if (pTarget[0] == 'g') + { + _result = create_shader(pTarget, buffer, buffer_size, file_name, (SGS*&)result, disasm); + } + else + { + NODEFAULT; + } + + if (disasm) + { + ID3DBlob* disasm = 0; + D3DDisassemble(buffer, buffer_size, FALSE, 0, &disasm); + // D3DXDisassembleShader (LPDWORD(code->GetBufferPointer()), FALSE, 0, &disasm ); + string_path dname; + strconcat(sizeof(dname), dname, "disasm\\", file_name, + ('v' == pTarget[0]) ? ".vs" : ('p' == pTarget[0]) ? ".ps" : ".gs"); + IWriter* W = FS.w_open("$logs$", dname); + W->w(disasm->GetBufferPointer(), (u32)disasm->GetBufferSize()); + FS.w_close(W); + _RELEASE(disasm); + } + + return _result; +} + +class includer : public ID3DInclude +{ +public: + HRESULT __stdcall Open( + D3D10_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) + { + string_path pname; + strconcat(sizeof(pname), pname, GEnv.Render->getShaderPath(), pFileName); + IReader* R = FS.r_open("$game_shaders$", pname); + if (nullptr == R) + { + // possibly in shared directory or somewhere else - open directly + R = FS.r_open("$game_shaders$", pFileName); + if (nullptr == R) + return E_FAIL; + } + + // duplicate and zero-terminate + u32 size = R->length(); + u8* data = xr_alloc(size + 1); + CopyMemory(data, R->pointer(), size); + data[size] = 0; + FS.r_close(R); + + *ppData = data; + *pBytes = size; + return D3D_OK; + } + HRESULT __stdcall Close(LPCVOID pData) + { + xr_free(pData); + return D3D_OK; + } +}; + +static inline bool match_shader_id( + LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result); + +HRESULT CRender::shader_compile(LPCSTR name, DWORD const* pSrcData, UINT SrcDataLen, LPCSTR pFunctionName, + LPCSTR pTarget, DWORD Flags, void*& result) +{ + D3D_SHADER_MACRO defines[128]; + int def_it = 0; + char c_smapsize[32]; + char c_gloss[32]; + char c_sun_shafts[32]; + char c_ssao[32]; + char c_sun_quality[32]; + + char sh_name[MAX_PATH] = ""; + u32 len = 0; + // options + { + xr_sprintf(c_smapsize, "%04d", u32(o.smapsize)); + defines[def_it].Name = "SMAP_size"; + defines[def_it].Definition = c_smapsize; + def_it++; + VERIFY(xr_strlen(c_smapsize) == 4 || atoi(c_smapsize) < 16384); + xr_strcat(sh_name, c_smapsize); + len += 4; + } + + if (o.fp16_filter) + { + defines[def_it].Name = "FP16_FILTER"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.fp16_filter); + ++len; + + if (o.fp16_blend) + { + defines[def_it].Name = "FP16_BLEND"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.fp16_blend); + ++len; + + if (o.HW_smap) + { + defines[def_it].Name = "USE_HWSMAP"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.HW_smap); + ++len; + + if (o.HW_smap_PCF) + { + defines[def_it].Name = "USE_HWSMAP_PCF"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.HW_smap_PCF); + ++len; + + if (o.HW_smap_FETCH4) + { + defines[def_it].Name = "USE_FETCH4"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.HW_smap_FETCH4); + ++len; + + if (o.sjitter) + { + defines[def_it].Name = "USE_SJITTER"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.sjitter); + ++len; + + if (HW.Caps.raster_major >= 3) + { + defines[def_it].Name = "USE_BRANCHING"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(HW.Caps.raster_major >= 3); + ++len; + + if (HW.Caps.geometry.bVTF) + { + defines[def_it].Name = "USE_VTF"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(HW.Caps.geometry.bVTF); + ++len; + + if (o.Tshadows) + { + defines[def_it].Name = "USE_TSHADOWS"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.Tshadows); + ++len; + + if (o.mblur) + { + defines[def_it].Name = "USE_MBLUR"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.mblur); + ++len; + + if (o.sunfilter) + { + defines[def_it].Name = "USE_SUNFILTER"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.sunfilter); + ++len; + + if (o.sunstatic) + { + defines[def_it].Name = "USE_R2_STATIC_SUN"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.sunstatic); + ++len; + + if (o.forcegloss) + { + xr_sprintf(c_gloss, "%f", o.forcegloss_v); + defines[def_it].Name = "FORCE_GLOSS"; + defines[def_it].Definition = c_gloss; + def_it++; + } + sh_name[len] = '0' + char(o.forcegloss); + ++len; + + if (o.forceskinw) + { + defines[def_it].Name = "SKIN_COLOR"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.forceskinw); + ++len; + + if (o.ssao_blur_on) + { + defines[def_it].Name = "USE_SSAO_BLUR"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.ssao_blur_on); + ++len; + + if (o.ssao_hdao) + { + defines[def_it].Name = "HDAO"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.ssao_hdao); + ++len; + + if (o.ssao_hbao) + { + defines[def_it].Name = "USE_HBAO"; + defines[def_it].Definition = "1"; + def_it++; + if (o.hbao_vectorized) + { + defines[def_it].Name = "VECTORIZED_CODE"; + defines[def_it].Definition = "1"; + def_it++; + } + } + sh_name[len] = '0' + char(o.ssao_hbao); + ++len; + sh_name[len] = '0' + char(o.ssao_hbao ? o.hbao_vectorized : 0); + ++len; + + if (o.ssao_opt_data) + { + defines[def_it].Name = "SSAO_OPT_DATA"; + if (o.ssao_half_data) + defines[def_it].Definition = "2"; + else + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.ssao_opt_data ? (o.ssao_half_data ? 2 : 1) : 0); + ++len; + + // skinning + if (m_skinning < 0) + { + defines[def_it].Name = "SKIN_NONE"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (0 == m_skinning) + { + defines[def_it].Name = "SKIN_0"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(0 == m_skinning); + ++len; + + if (1 == m_skinning) + { + defines[def_it].Name = "SKIN_1"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(1 == m_skinning); + ++len; + + if (2 == m_skinning) + { + defines[def_it].Name = "SKIN_2"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(2 == m_skinning); + ++len; + + if (3 == m_skinning) + { + defines[def_it].Name = "SKIN_3"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(3 == m_skinning); + ++len; + + if (4 == m_skinning) + { + defines[def_it].Name = "SKIN_4"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(4 == m_skinning); + ++len; + + // Igor: need restart options + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_WATER)) + { + defines[def_it].Name = "USE_SOFT_WATER"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_PARTICLES)) + { + defines[def_it].Name = "USE_SOFT_PARTICLES"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_DOF)) + { + defines[def_it].Name = "USE_DOF"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r_sun_shafts) + { + xr_sprintf(c_sun_shafts, "%d", ps_r_sun_shafts); + defines[def_it].Name = "SUN_SHAFTS_QUALITY"; + defines[def_it].Definition = c_sun_shafts; + def_it++; + sh_name[len] = '0' + char(ps_r_sun_shafts); + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r_ssao) + { + xr_sprintf(c_ssao, "%d", ps_r_ssao); + defines[def_it].Name = "SSAO_QUALITY"; + defines[def_it].Definition = c_ssao; + def_it++; + sh_name[len] = '0' + char(ps_r_ssao); + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r_sun_quality) + { + xr_sprintf(c_sun_quality, "%d", ps_r_sun_quality); + defines[def_it].Name = "SUN_QUALITY"; + defines[def_it].Definition = c_sun_quality; + def_it++; + sh_name[len] = '0' + char(ps_r_sun_quality); + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_STEEP_PARALLAX)) + { + defines[def_it].Name = "ALLOW_STEEPPARALLAX"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (o.dx10_gbuffer_opt) + { + defines[def_it].Name = "GBUFFER_OPTIMIZATION"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.dx10_gbuffer_opt); + ++len; + + if (o.dx10_sm4_1) + { + defines[def_it].Name = "SM_4_1"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.dx10_sm4_1); + ++len; + + if (o.dx10_minmax_sm) + { + defines[def_it].Name = "USE_MINMAX_SM"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.dx10_minmax_sm != 0); + ++len; + + // Be carefull!!!!! this should be at the end to correctly generate + // compiled shader name; + // add a #define for DX10_1 MSAA support + if (o.dx10_msaa) + { + defines[def_it].Name = "USE_MSAA"; + defines[def_it].Definition = "1"; + def_it++; + + static char samples[2]; + + defines[def_it].Name = "MSAA_SAMPLES"; + samples[0] = char(o.dx10_msaa_samples) + '0'; + samples[1] = 0; + defines[def_it].Definition = samples; + def_it++; + + static char def[256]; + if (m_MSAASample < 0) + def[0] = '0'; + else + def[0] = '0' + char(m_MSAASample); + + def[1] = 0; + defines[def_it].Name = "ISAMPLE"; + defines[def_it].Definition = def; + def_it++; + + if (o.dx10_msaa_opt) + { + defines[def_it].Name = "MSAA_OPTIMIZATION"; + defines[def_it].Definition = "1"; + def_it++; + } + + sh_name[len] = '1'; + ++len; + sh_name[len] = '0' + char(o.dx10_msaa_samples); + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0' + char(o.dx10_msaa_opt); + ++len; + + switch (o.dx10_msaa_alphatest) + { + case MSAA_ATEST_DX10_0_ATOC: + defines[def_it].Name = "MSAA_ALPHATEST_DX10_0_ATOC"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + break; + case MSAA_ATEST_DX10_1_ATOC: + defines[def_it].Name = "MSAA_ALPHATEST_DX10_1_ATOC"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '0'; + ++len; + sh_name[len] = '1'; + ++len; + sh_name[len] = '0'; + ++len; + break; + case MSAA_ATEST_DX10_1_NATIVE: + defines[def_it].Name = "MSAA_ALPHATEST_DX10_1"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '1'; + ++len; + break; + default: + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + } + } + else + { + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + } + + sh_name[len] = '\0'; + + // finish + defines[def_it].Name = nullptr; + defines[def_it].Definition = nullptr; + def_it++; + + if (0 == xr_strcmp(pFunctionName, "main")) + { + if ('v' == pTarget[0]) + { + if (HW.pDevice1 == 0) + pTarget = D3D10GetVertexShaderProfile(HW.pDevice); // vertex "vs_4_0"; + else + pTarget = "vs_4_1"; // pixel "ps_4_0"; + } + else if ('p' == pTarget[0]) + { + if (HW.pDevice1 == 0) + pTarget = D3D10GetPixelShaderProfile(HW.pDevice); // pixel "ps_4_0"; + else + pTarget = "ps_4_1"; // pixel "ps_4_0"; + } + else if ('g' == pTarget[0]) + { + if (HW.pDevice1 == 0) + pTarget = D3D10GetGeometryShaderProfile(HW.pDevice); // geometry "gs_4_0"; + else + pTarget = "gs_4_1"; // pixel "ps_4_0"; + } + } + + HRESULT _result = E_FAIL; + + string_path folder_name, folder; + xr_strcpy(folder, "r3\\objects\\r3\\"); + xr_strcat(folder, name); + xr_strcat(folder, "."); + + char extension[3]; + strncpy_s(extension, pTarget, 2); + xr_strcat(folder, extension); + + FS.update_path(folder_name, "$game_shaders$", folder); + xr_strcat(folder_name, "\\"); + + m_file_set.clear(); + FS.file_list(m_file_set, folder_name, FS_ListFiles | FS_RootOnly, "*"); + + string_path temp_file_name, file_name; + if (!match_shader_id(name, sh_name, m_file_set, temp_file_name)) + { + string_path file; + xr_strcpy(file, "shaders_cache\\r3\\"); + xr_strcat(file, name); + xr_strcat(file, "."); + xr_strcat(file, extension); + xr_strcat(file, "\\"); + xr_strcat(file, sh_name); + FS.update_path(file_name, "$app_data_root$", file); + } + else + { + xr_strcpy(file_name, folder_name); + xr_strcat(file_name, temp_file_name); + } + + if (FS.exist(file_name)) + { + IReader* file = FS.r_open(file_name); + if (file->length() > 4) + { + u32 crc = file->r_u32(); + u32 crcComp = crc32(file->pointer(), file->elapsed()); + if (crcComp == crc) + _result = create_shader(pTarget, (DWORD*)file->pointer(), file->elapsed(), file_name, result, o.disasm); + } + file->close(); + } + + if (FAILED(_result)) + { + includer Includer; + LPD3DBLOB pShaderBuf = NULL; + LPD3DBLOB pErrorBuf = NULL; + _result = D3DCompile( + pSrcData, SrcDataLen, "", defines, &Includer, pFunctionName, pTarget, Flags, 0, &pShaderBuf, &pErrorBuf); + + if (SUCCEEDED(_result)) + { + IWriter* file = FS.w_open(file_name); + u32 crc = crc32(pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize()); + file->w_u32(crc); + file->w(pShaderBuf->GetBufferPointer(), (u32)pShaderBuf->GetBufferSize()); + FS.w_close(file); + + _result = create_shader(pTarget, (DWORD*)pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize(), + file_name, result, o.disasm); + } + else + { + Log("! ", file_name); + if (pErrorBuf) + Log("! error: ", (LPCSTR)pErrorBuf->GetBufferPointer()); + else + Msg("Can't compile shader hr=0x%08x", _result); + } + } + + return _result; +} + +static inline bool match_shader( + LPCSTR const debug_shader_id, LPCSTR const full_shader_id, LPCSTR const mask, size_t const mask_length) +{ + u32 const full_shader_id_length = xr_strlen(full_shader_id); + R_ASSERT2(full_shader_id_length == mask_length, + make_string("bad cache for shader %s, [%s], [%s]", debug_shader_id, mask, full_shader_id)); + char const* i = full_shader_id; + char const* const e = full_shader_id + full_shader_id_length; + char const* j = mask; + for (; i != e; ++i, ++j) + { + if (*i == *j) + continue; + + if (*j == '_') + continue; + + return false; + } + + return true; +} + +static inline bool match_shader_id( + LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result) +{ +#if 1 + strcpy_s(result, ""); + return false; +#else // #if 1 +#ifdef DEBUG + LPCSTR temp = ""; + bool found = false; + FS_FileSet::const_iterator i = file_set.begin(); + FS_FileSet::const_iterator const e = file_set.end(); + for (; i != e; ++i) + { + if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) + { + VERIFY(!found); + found = true; + temp = (*i).name.c_str(); + } + } + + xr_strcpy(result, temp); + return found; +#else // #ifdef DEBUG + FS_FileSet::const_iterator i = file_set.begin(); + FS_FileSet::const_iterator const e = file_set.end(); + for (; i != e; ++i) + { + if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) + { + xr_strcpy(result, (*i).name.c_str()); + return true; + } + } + + return false; +#endif // #ifdef DEBUG +#endif // #if 1 +} diff --git a/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj b/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj index ae1f041e2b3..68bf8fab6d6 100644 --- a/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj +++ b/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj @@ -530,6 +530,7 @@ + Create Create diff --git a/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj.filters b/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj.filters index f9eec142752..3ca8882d585 100644 --- a/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj.filters +++ b/src/Layers/xrRenderPC_R3/xrRender_R3.vcxproj.filters @@ -1277,6 +1277,9 @@ Core_Target + + Core + diff --git a/src/Layers/xrRenderPC_R4/r4.cpp b/src/Layers/xrRenderPC_R4/r4.cpp index 20605bf5251..2d8b24bff1b 100644 --- a/src/Layers/xrRenderPC_R4/r4.cpp +++ b/src/Layers/xrRenderPC_R4/r4.cpp @@ -770,881 +770,3 @@ void CRender::DumpStatistics(IGameFont& font, IPerformanceAlert* alert) HOM.DumpStatistics(font, alert); Sectors_xrc.DumpStatistics(font, alert); } - -void CRender::addShaderOption(const char* name, const char* value) -{ - D3D_SHADER_MACRO macro = {name, value}; - m_ShaderOptions.push_back(macro); -} - -template -static HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, - T*& result, bool const disasm) -{ - // XXX: disasm it - - result->sh = ShaderTypeTraits::CreateHWShader(buffer, buffer_size); - - ID3DShaderReflection* pReflection = 0; - -#ifdef USE_DX11 - HRESULT const _hr = D3DReflect(buffer, buffer_size, IID_ID3DShaderReflection, (void**)&pReflection); -#else - HRESULT const _hr = D3D10ReflectShader(buffer, buffer_size, &pReflection); -#endif - - if (SUCCEEDED(_hr) && pReflection) - { - // Parse constant table data - result->constants.parse(pReflection, ShaderTypeTraits::GetShaderDest()); - - _RELEASE(pReflection); - } - else - { - Msg("! D3DReflectShader %s hr == 0x%08x", file_name, _hr); - } - - return _hr; -} - -static HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, void*& result, bool const disasm) -{ - // XXX: what's going on with casts here??? - HRESULT _result = E_FAIL; - if (pTarget[0] == 'p') - { - _result = create_shader(pTarget, buffer, buffer_size, file_name, (SPS*&)result, disasm); - } - else if (pTarget[0] == 'v') - { - // XXX: try to use code below - // _result = create_shader(pTarget, buffer, buffer_size, file_name, (SVS*&)result, disasm); - - SVS* svs_result = (SVS*)result; -#ifdef USE_DX11 - _result = HW.pDevice->CreateVertexShader(buffer, buffer_size, 0, &svs_result->sh); -#else // #ifdef USE_DX11 - _result = HW.pDevice->CreateVertexShader(buffer, buffer_size, &svs_result->sh); -#endif // #ifdef USE_DX11 - - if (!SUCCEEDED(_result)) - { - Log("! VS: ", file_name); - Msg("! CreatePixelShader hr == 0x%08x", _result); - return E_FAIL; - } - - ID3DShaderReflection* pReflection = 0; -#ifdef USE_DX11 - _result = D3DReflect(buffer, buffer_size, IID_ID3DShaderReflection, (void**)&pReflection); -#else - _result = D3D10ReflectShader(buffer, buffer_size, &pReflection); -#endif - - // Parse constant, texture, sampler binding - // Store input signature blob - if (SUCCEEDED(_result) && pReflection) - { - // TODO: DX10: share the same input signatures - - // Store input signature (need only for VS) - // CHK_DX( D3DxxGetInputSignatureBlob(pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize(), - // &_vs->signature) ); - ID3DBlob* pSignatureBlob; - CHK_DX(D3DGetInputSignatureBlob(buffer, buffer_size, &pSignatureBlob)); - VERIFY(pSignatureBlob); - - svs_result->signature = RImplementation.Resources->_CreateInputSignature(pSignatureBlob); - - _RELEASE(pSignatureBlob); - - // Let constant table parse it's data - svs_result->constants.parse(pReflection, RC_dest_vertex); - - _RELEASE(pReflection); - } - else - { - Log("! VS: ", file_name); - Msg("! D3DXFindShaderComment hr == 0x%08x", _result); - } - } - else if (pTarget[0] == 'g') - { - _result = create_shader(pTarget, buffer, buffer_size, file_name, (SGS*&)result, disasm); - } - else if (pTarget[0] == 'c') - { - _result = create_shader(pTarget, buffer, buffer_size, file_name, (SCS*&)result, disasm); - } - else if (pTarget[0] == 'h') - { - _result = create_shader(pTarget, buffer, buffer_size, file_name, (SHS*&)result, disasm); - } - else if (pTarget[0] == 'd') - { - _result = create_shader(pTarget, buffer, buffer_size, file_name, (SDS*&)result, disasm); - } - else - { - NODEFAULT; - } - - if (disasm) - { - ID3DBlob* disasm = 0; - D3DDisassemble(buffer, buffer_size, FALSE, 0, &disasm); - // D3DXDisassembleShader (LPDWORD(code->GetBufferPointer()), FALSE, 0, &disasm ); - string_path dname; - strconcat(sizeof(dname), dname, "disasm\\", file_name, - ('v' == pTarget[0]) ? ".vs" : ('p' == pTarget[0]) ? ".ps" : ".gs"); - IWriter* W = FS.w_open("$logs$", dname); - W->w(disasm->GetBufferPointer(), (u32)disasm->GetBufferSize()); - FS.w_close(W); - _RELEASE(disasm); - } - - return _result; -} - -class includer : public ID3DInclude -{ -public: - HRESULT __stdcall Open( - D3D10_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) - { - string_path pname; - strconcat(sizeof(pname), pname, GEnv.Render->getShaderPath(), pFileName); - IReader* R = FS.r_open("$game_shaders$", pname); - if (nullptr == R) - { - // possibly in shared directory or somewhere else - open directly - R = FS.r_open("$game_shaders$", pFileName); - if (nullptr == R) - return E_FAIL; - } - - // duplicate and zero-terminate - u32 size = R->length(); - u8* data = xr_alloc(size + 1); - CopyMemory(data, R->pointer(), size); - data[size] = 0; - FS.r_close(R); - - *ppData = data; - *pBytes = size; - return D3D_OK; - } - HRESULT __stdcall Close(LPCVOID pData) - { - xr_free(pData); - return D3D_OK; - } -}; - -static inline bool match_shader_id( - LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result); - -HRESULT CRender::shader_compile(LPCSTR name, DWORD const* pSrcData, UINT SrcDataLen, LPCSTR pFunctionName, - LPCSTR pTarget, DWORD Flags, void*& result) -{ - D3D_SHADER_MACRO defines[128]; - int def_it = 0; - char c_smapsize[32]; - char c_sun_shafts[32]; - char c_ssao[32]; - char c_sun_quality[32]; - - char sh_name[MAX_PATH] = ""; - - for (u32 i = 0; i < m_ShaderOptions.size(); ++i) - { - defines[def_it++] = m_ShaderOptions[i]; - } - - u32 len = xr_strlen(sh_name); - // options - { - xr_sprintf(c_smapsize, "%04d", u32(o.smapsize)); - defines[def_it].Name = "SMAP_size"; - defines[def_it].Definition = c_smapsize; - def_it++; - VERIFY(xr_strlen(c_smapsize) == 4 || atoi(c_smapsize) < 16384); - xr_strcat(sh_name, c_smapsize); - len += 4; - } - - if (o.fp16_filter) - { - defines[def_it].Name = "FP16_FILTER"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.fp16_filter); - ++len; - - if (o.fp16_blend) - { - defines[def_it].Name = "FP16_BLEND"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.fp16_blend); - ++len; - - if (o.HW_smap) - { - defines[def_it].Name = "USE_HWSMAP"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.HW_smap); - ++len; - - if (o.HW_smap_PCF) - { - defines[def_it].Name = "USE_HWSMAP_PCF"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.HW_smap_PCF); - ++len; - - if (o.HW_smap_FETCH4) - { - defines[def_it].Name = "USE_FETCH4"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.HW_smap_FETCH4); - ++len; - - if (o.sjitter) - { - defines[def_it].Name = "USE_SJITTER"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.sjitter); - ++len; - - if (HW.Caps.raster_major >= 3) - { - defines[def_it].Name = "USE_BRANCHING"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(HW.Caps.raster_major >= 3); - ++len; - - if (HW.Caps.geometry.bVTF) - { - defines[def_it].Name = "USE_VTF"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(HW.Caps.geometry.bVTF); - ++len; - - if (o.Tshadows) - { - defines[def_it].Name = "USE_TSHADOWS"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.Tshadows); - ++len; - - if (o.mblur) - { - defines[def_it].Name = "USE_MBLUR"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.mblur); - ++len; - - if (o.sunfilter) - { - defines[def_it].Name = "USE_SUNFILTER"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.sunfilter); - ++len; - - if (o.sunstatic) - { - defines[def_it].Name = "USE_R2_STATIC_SUN"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.sunstatic); - ++len; - - if (o.forceskinw) - { - defines[def_it].Name = "SKIN_COLOR"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.forceskinw); - ++len; - - if (o.ssao_blur_on) - { - defines[def_it].Name = "USE_SSAO_BLUR"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.ssao_blur_on); - ++len; - - if (o.ssao_hdao) - { - defines[def_it].Name = "HDAO"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - sh_name[len] = '0' + char(o.ssao_hbao); - ++len; - sh_name[len] = '0' + char(o.ssao_half_data); - ++len; - if (o.ssao_hbao) - { - defines[def_it].Name = "SSAO_OPT_DATA"; - if (o.ssao_half_data) - { - defines[def_it].Definition = "2"; - } - else - { - defines[def_it].Definition = "1"; - } - def_it++; - - if (o.hbao_vectorized) - { - defines[def_it].Name = "VECTORIZED_CODE"; - defines[def_it].Definition = "1"; - def_it++; - } - - defines[def_it].Name = "USE_HBAO"; - defines[def_it].Definition = "1"; - def_it++; - } - } - - if (o.dx10_msaa) - { - static char def[256]; - // if( m_MSAASample < 0 ) - //{ - def[0] = '0'; - // sh_name[len]='0'; ++len; - //} - // else - //{ - // def[0]= '0' + char(m_MSAASample); - // sh_name[len]='0' + char(m_MSAASample); ++len; - //} - def[1] = 0; - defines[def_it].Name = "ISAMPLE"; - defines[def_it].Definition = def; - def_it++; - sh_name[len] = '0'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - // skinning - if (m_skinning < 0) - { - defines[def_it].Name = "SKIN_NONE"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (0 == m_skinning) - { - defines[def_it].Name = "SKIN_0"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(0 == m_skinning); - ++len; - - if (1 == m_skinning) - { - defines[def_it].Name = "SKIN_1"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(1 == m_skinning); - ++len; - - if (2 == m_skinning) - { - defines[def_it].Name = "SKIN_2"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(2 == m_skinning); - ++len; - - if (3 == m_skinning) - { - defines[def_it].Name = "SKIN_3"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(3 == m_skinning); - ++len; - - if (4 == m_skinning) - { - defines[def_it].Name = "SKIN_4"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(4 == m_skinning); - ++len; - - // Igor: need restart options - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_WATER)) - { - defines[def_it].Name = "USE_SOFT_WATER"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_PARTICLES)) - { - defines[def_it].Name = "USE_SOFT_PARTICLES"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_DOF)) - { - defines[def_it].Name = "USE_DOF"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r_sun_shafts) - { - xr_sprintf(c_sun_shafts, "%d", ps_r_sun_shafts); - defines[def_it].Name = "SUN_SHAFTS_QUALITY"; - defines[def_it].Definition = c_sun_shafts; - def_it++; - sh_name[len] = '0' + char(ps_r_sun_shafts); - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r_ssao) - { - xr_sprintf(c_ssao, "%d", ps_r_ssao); - defines[def_it].Name = "SSAO_QUALITY"; - defines[def_it].Definition = c_ssao; - def_it++; - sh_name[len] = '0' + char(ps_r_ssao); - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r_sun_quality) - { - xr_sprintf(c_sun_quality, "%d", ps_r_sun_quality); - defines[def_it].Name = "SUN_QUALITY"; - defines[def_it].Definition = c_sun_quality; - def_it++; - sh_name[len] = '0' + char(ps_r_sun_quality); - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_STEEP_PARALLAX)) - { - defines[def_it].Name = "ALLOW_STEEPPARALLAX"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - } - else - { - sh_name[len] = '0'; - ++len; - } - - if (o.dx10_gbuffer_opt) - { - defines[def_it].Name = "GBUFFER_OPTIMIZATION"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.dx10_gbuffer_opt); - ++len; - - // R_ASSERT ( !o.dx10_sm4_1 ); - if (o.dx10_sm4_1) - { - defines[def_it].Name = "SM_4_1"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.dx10_sm4_1); - ++len; - - R_ASSERT(HW.FeatureLevel >= D3D_FEATURE_LEVEL_11_0); - if (HW.FeatureLevel >= D3D_FEATURE_LEVEL_11_0) - { - defines[def_it].Name = "SM_5"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(HW.FeatureLevel >= D3D_FEATURE_LEVEL_11_0); - ++len; - - if (o.dx10_minmax_sm) - { - defines[def_it].Name = "USE_MINMAX_SM"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.dx10_minmax_sm != 0); - ++len; - - // Be carefull!!!!! this should be at the end to correctly generate - // compiled shader name; - // add a #define for DX10_1 MSAA support - if (o.dx10_msaa) - { - defines[def_it].Name = "USE_MSAA"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - - static char samples[2]; - - defines[def_it].Name = "MSAA_SAMPLES"; - samples[0] = char(o.dx10_msaa_samples) + '0'; - samples[1] = 0; - defines[def_it].Definition = samples; - def_it++; - sh_name[len] = '0' + char(o.dx10_msaa_samples); - ++len; - - if (o.dx10_msaa_opt) - { - defines[def_it].Name = "MSAA_OPTIMIZATION"; - defines[def_it].Definition = "1"; - def_it++; - } - sh_name[len] = '0' + char(o.dx10_msaa_opt); - ++len; - - switch (o.dx10_msaa_alphatest) - { - case MSAA_ATEST_DX10_0_ATOC: - defines[def_it].Name = "MSAA_ALPHATEST_DX10_0_ATOC"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '1'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - break; - case MSAA_ATEST_DX10_1_ATOC: - defines[def_it].Name = "MSAA_ALPHATEST_DX10_1_ATOC"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '0'; - ++len; - sh_name[len] = '1'; - ++len; - sh_name[len] = '0'; - ++len; - break; - case MSAA_ATEST_DX10_1_NATIVE: - defines[def_it].Name = "MSAA_ALPHATEST_DX10_1"; - defines[def_it].Definition = "1"; - def_it++; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '1'; - ++len; - break; - default: - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - } - } - else - { - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - sh_name[len] = '0'; - ++len; - } - - sh_name[len] = '\0'; - - // finish - defines[def_it].Name = nullptr; - defines[def_it].Definition = nullptr; - def_it++; - - if (0 == xr_strcmp(pFunctionName, "main")) - { - if ('v' == pTarget[0]) - { - if (HW.FeatureLevel == D3D_FEATURE_LEVEL_10_0) - pTarget = "vs_4_0"; - else if (HW.FeatureLevel == D3D_FEATURE_LEVEL_10_1) - pTarget = "vs_4_1"; - else if (HW.FeatureLevel == D3D_FEATURE_LEVEL_11_0) - pTarget = "vs_5_0"; - } - else if ('p' == pTarget[0]) - { - if (HW.FeatureLevel == D3D_FEATURE_LEVEL_10_0) - pTarget = "ps_4_0"; - else if (HW.FeatureLevel == D3D_FEATURE_LEVEL_10_1) - pTarget = "ps_4_1"; - else if (HW.FeatureLevel == D3D_FEATURE_LEVEL_11_0) - pTarget = "ps_5_0"; - } - else if ('g' == pTarget[0]) - { - if (HW.FeatureLevel == D3D_FEATURE_LEVEL_10_0) - pTarget = "gs_4_0"; - else if (HW.FeatureLevel == D3D_FEATURE_LEVEL_10_1) - pTarget = "gs_4_1"; - else if (HW.FeatureLevel == D3D_FEATURE_LEVEL_11_0) - pTarget = "gs_5_0"; - } - else if ('c' == pTarget[0]) - { - if (HW.FeatureLevel == D3D_FEATURE_LEVEL_11_0) - pTarget = "cs_5_0"; - } - } - - HRESULT _result = E_FAIL; - - string_path folder_name, folder; - xr_strcpy(folder, "r3\\objects\\r4\\"); - xr_strcat(folder, name); - xr_strcat(folder, "."); - - char extension[3]; - strncpy_s(extension, pTarget, 2); - xr_strcat(folder, extension); - - FS.update_path(folder_name, "$game_shaders$", folder); - xr_strcat(folder_name, "\\"); - - m_file_set.clear(); - FS.file_list(m_file_set, folder_name, FS_ListFiles | FS_RootOnly, "*"); - - string_path temp_file_name, file_name; - if (!match_shader_id(name, sh_name, m_file_set, temp_file_name)) - { - string_path file; - xr_strcpy(file, "shaders_cache\\r4\\"); - xr_strcat(file, name); - xr_strcat(file, "."); - xr_strcat(file, extension); - xr_strcat(file, "\\"); - xr_strcat(file, sh_name); - FS.update_path(file_name, "$app_data_root$", file); - } - else - { - xr_strcpy(file_name, folder_name); - xr_strcat(file_name, temp_file_name); - } - - if (FS.exist(file_name)) - { - IReader* file = FS.r_open(file_name); - if (file->length() > 4) - { - u32 crc = file->r_u32(); - u32 crcComp = crc32(file->pointer(), file->elapsed()); - if (crcComp == crc) - _result = create_shader(pTarget, (DWORD*)file->pointer(), file->elapsed(), file_name, result, o.disasm); - } - file->close(); - } - - if (FAILED(_result)) - { - includer Includer; - LPD3DBLOB pShaderBuf = NULL; - LPD3DBLOB pErrorBuf = NULL; - _result = D3DCompile(pSrcData, SrcDataLen, "", defines, &Includer, pFunctionName, pTarget, Flags, 0, &pShaderBuf, &pErrorBuf); - - if (SUCCEEDED(_result)) - { - IWriter* file = FS.w_open(file_name); - u32 crc = crc32(pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize()); - file->w_u32(crc); - file->w(pShaderBuf->GetBufferPointer(), (u32)pShaderBuf->GetBufferSize()); - FS.w_close(file); - - _result = create_shader(pTarget, (DWORD*)pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize(), - file_name, result, o.disasm); - } - else - { - Log("! ", file_name); - if (pErrorBuf) - Log("! error: ", (LPCSTR)pErrorBuf->GetBufferPointer()); - else - Msg("Can't compile shader hr=0x%08x", _result); - } - } - - return _result; -} - -static inline bool match_shader( - LPCSTR const debug_shader_id, LPCSTR const full_shader_id, LPCSTR const mask, size_t const mask_length) -{ - u32 const full_shader_id_length = xr_strlen(full_shader_id); - R_ASSERT2(full_shader_id_length == mask_length, - make_string("bad cache for shader %s, [%s], [%s]", debug_shader_id, mask, full_shader_id)); - char const* i = full_shader_id; - char const* const e = full_shader_id + full_shader_id_length; - char const* j = mask; - for (; i != e; ++i, ++j) - { - if (*i == *j) - continue; - - if (*j == '_') - continue; - - return false; - } - - return true; -} - -static inline bool match_shader_id( - LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result) -{ -#if 1 - strcpy_s ( result, "" ); - return false; -#else // #if 1 -#ifdef DEBUG - LPCSTR temp = ""; - bool found = false; - FS_FileSet::const_iterator i = file_set.begin(); - FS_FileSet::const_iterator const e = file_set.end(); - for (; i != e; ++i) - { - if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) - { - VERIFY(!found); - found = true; - temp = (*i).name.c_str(); - } - } - - xr_strcpy(result, temp); - return found; -#else // #ifdef DEBUG - FS_FileSet::const_iterator i = file_set.begin(); - FS_FileSet::const_iterator const e = file_set.end(); - for (; i != e; ++i) - { - if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) - { - xr_strcpy(result, (*i).name.c_str()); - return true; - } - } - - return false; -#endif // #ifdef DEBUG -#endif // #if 1 -} diff --git a/src/Layers/xrRenderPC_R4/r4_shaders.cpp b/src/Layers/xrRenderPC_R4/r4_shaders.cpp new file mode 100644 index 00000000000..e47b9261ecc --- /dev/null +++ b/src/Layers/xrRenderPC_R4/r4_shaders.cpp @@ -0,0 +1,870 @@ +#include "stdafx.h" +#include "r4.h" +#include "Layers/xrRender/ShaderResourceTraits.h" + +void CRender::addShaderOption(const char* name, const char* value) +{ + D3D_SHADER_MACRO macro = {name, value}; + m_ShaderOptions.push_back(macro); +} + +template +static HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, + T*& result, bool const disasm) +{ + // XXX: disasm it + + result->sh = ShaderTypeTraits::CreateHWShader(buffer, buffer_size); + + ID3DShaderReflection* pReflection = 0; + HRESULT const _hr = D3DReflect(buffer, buffer_size, IID_ID3DShaderReflection, (void**)&pReflection); + + if (SUCCEEDED(_hr) && pReflection) + { + // Parse constant table data + result->constants.parse(pReflection, ShaderTypeTraits::GetShaderDest()); + + _RELEASE(pReflection); + } + else + { + Msg("! D3DReflectShader %s hr == 0x%08x", file_name, _hr); + } + + return _hr; +} + +static HRESULT create_shader(LPCSTR const pTarget, DWORD const* buffer, u32 const buffer_size, LPCSTR const file_name, + void*& result, bool const disasm) +{ + // XXX: what's going on with casts here??? + HRESULT _result = E_FAIL; + if (pTarget[0] == 'p') + { + _result = create_shader(pTarget, buffer, buffer_size, file_name, (SPS*&)result, disasm); + } + else if (pTarget[0] == 'v') + { + // XXX: try to use code below + // _result = create_shader(pTarget, buffer, buffer_size, file_name, (SVS*&)result, disasm); + + SVS* svs_result = (SVS*)result; + _result = HW.pDevice->CreateVertexShader(buffer, buffer_size, 0, &svs_result->sh); + + if (!SUCCEEDED(_result)) + { + Log("! VS: ", file_name); + Msg("! CreatePixelShader hr == 0x%08x", _result); + return E_FAIL; + } + + ID3DShaderReflection* pReflection = 0; + _result = D3DReflect(buffer, buffer_size, IID_ID3DShaderReflection, (void**)&pReflection); + + // Parse constant, texture, sampler binding + // Store input signature blob + if (SUCCEEDED(_result) && pReflection) + { + // TODO: DX10: share the same input signatures + + // Store input signature (need only for VS) + // CHK_DX( D3DxxGetInputSignatureBlob(pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize(), + // &_vs->signature) ); + ID3DBlob* pSignatureBlob; + CHK_DX(D3DGetInputSignatureBlob(buffer, buffer_size, &pSignatureBlob)); + VERIFY(pSignatureBlob); + + svs_result->signature = RImplementation.Resources->_CreateInputSignature(pSignatureBlob); + + _RELEASE(pSignatureBlob); + + // Let constant table parse it's data + svs_result->constants.parse(pReflection, RC_dest_vertex); + + _RELEASE(pReflection); + } + else + { + Log("! VS: ", file_name); + Msg("! D3DXFindShaderComment hr == 0x%08x", _result); + } + } + else if (pTarget[0] == 'g') + { + _result = create_shader(pTarget, buffer, buffer_size, file_name, (SGS*&)result, disasm); + } + else if (pTarget[0] == 'c') + { + _result = create_shader(pTarget, buffer, buffer_size, file_name, (SCS*&)result, disasm); + } + else if (pTarget[0] == 'h') + { + _result = create_shader(pTarget, buffer, buffer_size, file_name, (SHS*&)result, disasm); + } + else if (pTarget[0] == 'd') + { + _result = create_shader(pTarget, buffer, buffer_size, file_name, (SDS*&)result, disasm); + } + else + { + NODEFAULT; + } + + if (disasm) + { + ID3DBlob* disasm = 0; + D3DDisassemble(buffer, buffer_size, FALSE, 0, &disasm); + // D3DXDisassembleShader (LPDWORD(code->GetBufferPointer()), FALSE, 0, &disasm ); + string_path dname; + strconcat(sizeof(dname), dname, "disasm\\", file_name, + ('v' == pTarget[0]) ? ".vs" : ('p' == pTarget[0]) ? ".ps" : ".gs"); + IWriter* W = FS.w_open("$logs$", dname); + W->w(disasm->GetBufferPointer(), (u32)disasm->GetBufferSize()); + FS.w_close(W); + _RELEASE(disasm); + } + + return _result; +} + +class includer : public ID3DInclude +{ +public: + HRESULT __stdcall Open( + D3D10_INCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes) + { + string_path pname; + strconcat(sizeof(pname), pname, GEnv.Render->getShaderPath(), pFileName); + IReader* R = FS.r_open("$game_shaders$", pname); + if (nullptr == R) + { + // possibly in shared directory or somewhere else - open directly + R = FS.r_open("$game_shaders$", pFileName); + if (nullptr == R) + return E_FAIL; + } + + // duplicate and zero-terminate + u32 size = R->length(); + u8* data = xr_alloc(size + 1); + CopyMemory(data, R->pointer(), size); + data[size] = 0; + FS.r_close(R); + + *ppData = data; + *pBytes = size; + return D3D_OK; + } + HRESULT __stdcall Close(LPCVOID pData) + { + xr_free(pData); + return D3D_OK; + } +}; + +static inline bool match_shader_id( + LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result); + +HRESULT CRender::shader_compile(LPCSTR name, DWORD const* pSrcData, UINT SrcDataLen, LPCSTR pFunctionName, + LPCSTR pTarget, DWORD Flags, void*& result) +{ + D3D_SHADER_MACRO defines[128]; + int def_it = 0; + char c_smapsize[32]; + char c_sun_shafts[32]; + char c_ssao[32]; + char c_sun_quality[32]; + + char sh_name[MAX_PATH] = ""; + + for (u32 i = 0; i < m_ShaderOptions.size(); ++i) + { + defines[def_it++] = m_ShaderOptions[i]; + } + + u32 len = xr_strlen(sh_name); + // options + { + xr_sprintf(c_smapsize, "%04d", u32(o.smapsize)); + defines[def_it].Name = "SMAP_size"; + defines[def_it].Definition = c_smapsize; + def_it++; + VERIFY(xr_strlen(c_smapsize) == 4 || atoi(c_smapsize) < 16384); + xr_strcat(sh_name, c_smapsize); + len += 4; + } + + if (o.fp16_filter) + { + defines[def_it].Name = "FP16_FILTER"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.fp16_filter); + ++len; + + if (o.fp16_blend) + { + defines[def_it].Name = "FP16_BLEND"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.fp16_blend); + ++len; + + if (o.HW_smap) + { + defines[def_it].Name = "USE_HWSMAP"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.HW_smap); + ++len; + + if (o.HW_smap_PCF) + { + defines[def_it].Name = "USE_HWSMAP_PCF"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.HW_smap_PCF); + ++len; + + if (o.HW_smap_FETCH4) + { + defines[def_it].Name = "USE_FETCH4"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.HW_smap_FETCH4); + ++len; + + if (o.sjitter) + { + defines[def_it].Name = "USE_SJITTER"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.sjitter); + ++len; + + if (HW.Caps.raster_major >= 3) + { + defines[def_it].Name = "USE_BRANCHING"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(HW.Caps.raster_major >= 3); + ++len; + + if (HW.Caps.geometry.bVTF) + { + defines[def_it].Name = "USE_VTF"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(HW.Caps.geometry.bVTF); + ++len; + + if (o.Tshadows) + { + defines[def_it].Name = "USE_TSHADOWS"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.Tshadows); + ++len; + + if (o.mblur) + { + defines[def_it].Name = "USE_MBLUR"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.mblur); + ++len; + + if (o.sunfilter) + { + defines[def_it].Name = "USE_SUNFILTER"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.sunfilter); + ++len; + + if (o.sunstatic) + { + defines[def_it].Name = "USE_R2_STATIC_SUN"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.sunstatic); + ++len; + + if (o.forceskinw) + { + defines[def_it].Name = "SKIN_COLOR"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.forceskinw); + ++len; + + if (o.ssao_blur_on) + { + defines[def_it].Name = "USE_SSAO_BLUR"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.ssao_blur_on); + ++len; + + if (o.ssao_hdao) + { + defines[def_it].Name = "HDAO"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + sh_name[len] = '0' + char(o.ssao_hbao); + ++len; + sh_name[len] = '0' + char(o.ssao_half_data); + ++len; + if (o.ssao_hbao) + { + defines[def_it].Name = "SSAO_OPT_DATA"; + if (o.ssao_half_data) + { + defines[def_it].Definition = "2"; + } + else + { + defines[def_it].Definition = "1"; + } + def_it++; + + if (o.hbao_vectorized) + { + defines[def_it].Name = "VECTORIZED_CODE"; + defines[def_it].Definition = "1"; + def_it++; + } + + defines[def_it].Name = "USE_HBAO"; + defines[def_it].Definition = "1"; + def_it++; + } + } + + if (o.dx10_msaa) + { + static char def[256]; + // if( m_MSAASample < 0 ) + //{ + def[0] = '0'; + // sh_name[len]='0'; ++len; + //} + // else + //{ + // def[0]= '0' + char(m_MSAASample); + // sh_name[len]='0' + char(m_MSAASample); ++len; + //} + def[1] = 0; + defines[def_it].Name = "ISAMPLE"; + defines[def_it].Definition = def; + def_it++; + sh_name[len] = '0'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + // skinning + if (m_skinning < 0) + { + defines[def_it].Name = "SKIN_NONE"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (0 == m_skinning) + { + defines[def_it].Name = "SKIN_0"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(0 == m_skinning); + ++len; + + if (1 == m_skinning) + { + defines[def_it].Name = "SKIN_1"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(1 == m_skinning); + ++len; + + if (2 == m_skinning) + { + defines[def_it].Name = "SKIN_2"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(2 == m_skinning); + ++len; + + if (3 == m_skinning) + { + defines[def_it].Name = "SKIN_3"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(3 == m_skinning); + ++len; + + if (4 == m_skinning) + { + defines[def_it].Name = "SKIN_4"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(4 == m_skinning); + ++len; + + // Igor: need restart options + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_WATER)) + { + defines[def_it].Name = "USE_SOFT_WATER"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_SOFT_PARTICLES)) + { + defines[def_it].Name = "USE_SOFT_PARTICLES"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_DOF)) + { + defines[def_it].Name = "USE_DOF"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r_sun_shafts) + { + xr_sprintf(c_sun_shafts, "%d", ps_r_sun_shafts); + defines[def_it].Name = "SUN_SHAFTS_QUALITY"; + defines[def_it].Definition = c_sun_shafts; + def_it++; + sh_name[len] = '0' + char(ps_r_sun_shafts); + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r_ssao) + { + xr_sprintf(c_ssao, "%d", ps_r_ssao); + defines[def_it].Name = "SSAO_QUALITY"; + defines[def_it].Definition = c_ssao; + def_it++; + sh_name[len] = '0' + char(ps_r_ssao); + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r_sun_quality) + { + xr_sprintf(c_sun_quality, "%d", ps_r_sun_quality); + defines[def_it].Name = "SUN_QUALITY"; + defines[def_it].Definition = c_sun_quality; + def_it++; + sh_name[len] = '0' + char(ps_r_sun_quality); + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (RImplementation.o.advancedpp && ps_r2_ls_flags.test(R2FLAG_STEEP_PARALLAX)) + { + defines[def_it].Name = "ALLOW_STEEPPARALLAX"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + } + else + { + sh_name[len] = '0'; + ++len; + } + + if (o.dx10_gbuffer_opt) + { + defines[def_it].Name = "GBUFFER_OPTIMIZATION"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.dx10_gbuffer_opt); + ++len; + + // R_ASSERT ( !o.dx10_sm4_1 ); + if (o.dx10_sm4_1) + { + defines[def_it].Name = "SM_4_1"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.dx10_sm4_1); + ++len; + + R_ASSERT(HW.FeatureLevel >= D3D_FEATURE_LEVEL_11_0); + if (HW.FeatureLevel >= D3D_FEATURE_LEVEL_11_0) + { + defines[def_it].Name = "SM_5"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(HW.FeatureLevel >= D3D_FEATURE_LEVEL_11_0); + ++len; + + if (o.dx10_minmax_sm) + { + defines[def_it].Name = "USE_MINMAX_SM"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.dx10_minmax_sm != 0); + ++len; + + // Be carefull!!!!! this should be at the end to correctly generate + // compiled shader name; + // add a #define for DX10_1 MSAA support + if (o.dx10_msaa) + { + defines[def_it].Name = "USE_MSAA"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + + static char samples[2]; + + defines[def_it].Name = "MSAA_SAMPLES"; + samples[0] = char(o.dx10_msaa_samples) + '0'; + samples[1] = 0; + defines[def_it].Definition = samples; + def_it++; + sh_name[len] = '0' + char(o.dx10_msaa_samples); + ++len; + + if (o.dx10_msaa_opt) + { + defines[def_it].Name = "MSAA_OPTIMIZATION"; + defines[def_it].Definition = "1"; + def_it++; + } + sh_name[len] = '0' + char(o.dx10_msaa_opt); + ++len; + + switch (o.dx10_msaa_alphatest) + { + case MSAA_ATEST_DX10_0_ATOC: + defines[def_it].Name = "MSAA_ALPHATEST_DX10_0_ATOC"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '1'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + break; + case MSAA_ATEST_DX10_1_ATOC: + defines[def_it].Name = "MSAA_ALPHATEST_DX10_1_ATOC"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '0'; + ++len; + sh_name[len] = '1'; + ++len; + sh_name[len] = '0'; + ++len; + break; + case MSAA_ATEST_DX10_1_NATIVE: + defines[def_it].Name = "MSAA_ALPHATEST_DX10_1"; + defines[def_it].Definition = "1"; + def_it++; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '1'; + ++len; + break; + default: + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + } + } + else + { + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + sh_name[len] = '0'; + ++len; + } + + sh_name[len] = '\0'; + + // finish + defines[def_it].Name = nullptr; + defines[def_it].Definition = nullptr; + def_it++; + + if (0 == xr_strcmp(pFunctionName, "main")) + { + if ('v' == pTarget[0]) + { + if (HW.FeatureLevel == D3D_FEATURE_LEVEL_10_0) + pTarget = "vs_4_0"; + else if (HW.FeatureLevel == D3D_FEATURE_LEVEL_10_1) + pTarget = "vs_4_1"; + else if (HW.FeatureLevel == D3D_FEATURE_LEVEL_11_0) + pTarget = "vs_5_0"; + } + else if ('p' == pTarget[0]) + { + if (HW.FeatureLevel == D3D_FEATURE_LEVEL_10_0) + pTarget = "ps_4_0"; + else if (HW.FeatureLevel == D3D_FEATURE_LEVEL_10_1) + pTarget = "ps_4_1"; + else if (HW.FeatureLevel == D3D_FEATURE_LEVEL_11_0) + pTarget = "ps_5_0"; + } + else if ('g' == pTarget[0]) + { + if (HW.FeatureLevel == D3D_FEATURE_LEVEL_10_0) + pTarget = "gs_4_0"; + else if (HW.FeatureLevel == D3D_FEATURE_LEVEL_10_1) + pTarget = "gs_4_1"; + else if (HW.FeatureLevel == D3D_FEATURE_LEVEL_11_0) + pTarget = "gs_5_0"; + } + else if ('c' == pTarget[0]) + { + if (HW.FeatureLevel == D3D_FEATURE_LEVEL_11_0) + pTarget = "cs_5_0"; + } + } + + HRESULT _result = E_FAIL; + + string_path folder_name, folder; + xr_strcpy(folder, "r3\\objects\\r4\\"); + xr_strcat(folder, name); + xr_strcat(folder, "."); + + char extension[3]; + strncpy_s(extension, pTarget, 2); + xr_strcat(folder, extension); + + FS.update_path(folder_name, "$game_shaders$", folder); + xr_strcat(folder_name, "\\"); + + m_file_set.clear(); + FS.file_list(m_file_set, folder_name, FS_ListFiles | FS_RootOnly, "*"); + + string_path temp_file_name, file_name; + if (!match_shader_id(name, sh_name, m_file_set, temp_file_name)) + { + string_path file; + xr_strcpy(file, "shaders_cache\\r4\\"); + xr_strcat(file, name); + xr_strcat(file, "."); + xr_strcat(file, extension); + xr_strcat(file, "\\"); + xr_strcat(file, sh_name); + FS.update_path(file_name, "$app_data_root$", file); + } + else + { + xr_strcpy(file_name, folder_name); + xr_strcat(file_name, temp_file_name); + } + + if (FS.exist(file_name)) + { + IReader* file = FS.r_open(file_name); + if (file->length() > 4) + { + u32 crc = file->r_u32(); + u32 crcComp = crc32(file->pointer(), file->elapsed()); + if (crcComp == crc) + _result = create_shader(pTarget, (DWORD*)file->pointer(), file->elapsed(), file_name, result, o.disasm); + } + file->close(); + } + + if (FAILED(_result)) + { + includer Includer; + LPD3DBLOB pShaderBuf = NULL; + LPD3DBLOB pErrorBuf = NULL; + _result = D3DCompile( + pSrcData, SrcDataLen, "", defines, &Includer, pFunctionName, pTarget, Flags, 0, &pShaderBuf, &pErrorBuf); + + if (SUCCEEDED(_result)) + { + IWriter* file = FS.w_open(file_name); + u32 crc = crc32(pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize()); + file->w_u32(crc); + file->w(pShaderBuf->GetBufferPointer(), (u32)pShaderBuf->GetBufferSize()); + FS.w_close(file); + + _result = create_shader(pTarget, (DWORD*)pShaderBuf->GetBufferPointer(), pShaderBuf->GetBufferSize(), + file_name, result, o.disasm); + } + else + { + Log("! ", file_name); + if (pErrorBuf) + Log("! error: ", (LPCSTR)pErrorBuf->GetBufferPointer()); + else + Msg("Can't compile shader hr=0x%08x", _result); + } + } + + return _result; +} + +static inline bool match_shader( + LPCSTR const debug_shader_id, LPCSTR const full_shader_id, LPCSTR const mask, size_t const mask_length) +{ + u32 const full_shader_id_length = xr_strlen(full_shader_id); + R_ASSERT2(full_shader_id_length == mask_length, + make_string("bad cache for shader %s, [%s], [%s]", debug_shader_id, mask, full_shader_id)); + char const* i = full_shader_id; + char const* const e = full_shader_id + full_shader_id_length; + char const* j = mask; + for (; i != e; ++i, ++j) + { + if (*i == *j) + continue; + + if (*j == '_') + continue; + + return false; + } + + return true; +} + +static inline bool match_shader_id( + LPCSTR const debug_shader_id, LPCSTR const full_shader_id, FS_FileSet const& file_set, string_path& result) +{ +#if 1 + strcpy_s(result, ""); + return false; +#else // #if 1 +#ifdef DEBUG + LPCSTR temp = ""; + bool found = false; + FS_FileSet::const_iterator i = file_set.begin(); + FS_FileSet::const_iterator const e = file_set.end(); + for (; i != e; ++i) + { + if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) + { + VERIFY(!found); + found = true; + temp = (*i).name.c_str(); + } + } + + xr_strcpy(result, temp); + return found; +#else // #ifdef DEBUG + FS_FileSet::const_iterator i = file_set.begin(); + FS_FileSet::const_iterator const e = file_set.end(); + for (; i != e; ++i) + { + if (match_shader(debug_shader_id, full_shader_id, (*i).name.c_str(), (*i).name.size())) + { + xr_strcpy(result, (*i).name.c_str()); + return true; + } + } + + return false; +#endif // #ifdef DEBUG +#endif // #if 1 +} diff --git a/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj b/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj index f42fefa7705..3b99ed6e41c 100644 --- a/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj +++ b/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj @@ -540,6 +540,7 @@ + Create diff --git a/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj.filters b/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj.filters index 10d1e54224f..6703c86f2a9 100644 --- a/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj.filters +++ b/src/Layers/xrRenderPC_R4/xrRender_R4.vcxproj.filters @@ -1313,6 +1313,9 @@ Shading templates + + Core +