Example #1
0
void ShaderCache::Init()
{
	s_compiler = &HLSLAsyncCompiler::getInstance();
	s_shaders_lock.unlock();
	s_pass_entry.m_compiled = true;
	s_pass_entry.m_initialized.test_and_set();
	// This class intentionally shares its shader cache files with DX11, as the shaders are (right now) identical.
	// Reduces unnecessary compilation when switching between APIs.
	s_last_domain_shader_bytecode = &s_pass_entry;
	s_last_hull_shader_bytecode = &s_pass_entry;
	s_last_geometry_shader_bytecode = &s_pass_entry;
	s_last_pixel_shader_bytecode = nullptr;
	s_last_vertex_shader_bytecode = nullptr;

	s_last_geometry_shader_uid = {};
	s_last_pixel_shader_uid = {};
	s_last_vertex_shader_uid = {};
	s_last_tessellation_shader_uid = {};

	s_last_cpu_geometry_shader_uid = {};
	s_last_cpu_pixel_shader_uid = {};
	s_last_cpu_vertex_shader_uid = {};
	s_last_cpu_tessellation_shader_uid = {};

	// Ensure shader cache directory exists..
	std::string shader_cache_path = File::GetUserPath(D_SHADERCACHE_IDX);

	if (!File::Exists(shader_cache_path))
		File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));

	std::string title_unique_id = SConfig::GetInstance().m_strGameID;

	std::string ds_cache_filename = StringFromFormat("%sIDX11-%s-ds.cache", shader_cache_path.c_str(), title_unique_id.c_str());
	std::string hs_cache_filename = StringFromFormat("%sIDX11-%s-hs.cache", shader_cache_path.c_str(), title_unique_id.c_str());
	std::string gs_cache_filename = StringFromFormat("%sIDX11-%s-gs.cache", shader_cache_path.c_str(), title_unique_id.c_str());
	std::string ps_cache_filename = StringFromFormat("%sIDX11-%s-ps.cache", shader_cache_path.c_str(), title_unique_id.c_str());
	std::string vs_cache_filename = StringFromFormat("%sIDX11-%s-vs.cache", shader_cache_path.c_str(), title_unique_id.c_str());

	pKey_t gameid = (pKey_t)GetMurmurHash3(reinterpret_cast<const u8*>(SConfig::GetInstance().m_strGameID.data()), (u32)SConfig::GetInstance().m_strGameID.size(), 0);

	vs_bytecode_cache = VsBytecodeCache::Create(
		gameid,
		VERTEXSHADERGEN_UID_VERSION,
		"Ishiiruka.vs",
		StringFromFormat("%s.vs", title_unique_id.c_str())
	);

	ps_bytecode_cache = PsBytecodeCache::Create(
		gameid,
		PIXELSHADERGEN_UID_VERSION,
		"Ishiiruka.ps",
		StringFromFormat("%s.ps", title_unique_id.c_str())
	);

	gs_bytecode_cache = GsBytecodeCache::Create(
		gameid,
		GEOMETRYSHADERGEN_UID_VERSION,
		"Ishiiruka.gs",
		StringFromFormat("%s.gs", title_unique_id.c_str())
	);

	ts_bytecode_cache = TsBytecodeCache::Create(
		gameid,
		TESSELLATIONSHADERGEN_UID_VERSION,
		"Ishiiruka.ts",
		StringFromFormat("%s.ts", title_unique_id.c_str())
	);

	DShaderCacheInserter ds_inserter;
	s_ds_disk_cache.OpenAndRead(ds_cache_filename, ds_inserter);

	HShaderCacheInserter hs_inserter;
	s_hs_disk_cache.OpenAndRead(hs_cache_filename, hs_inserter);

	ShaderCacheInserter<GeometryShaderUid, GsBytecodeCache, &gs_bytecode_cache> gs_inserter;
	s_gs_disk_cache.OpenAndRead(gs_cache_filename, gs_inserter);

	ShaderCacheInserter<PixelShaderUid, PsBytecodeCache, &ps_bytecode_cache> ps_inserter;
	s_ps_disk_cache.OpenAndRead(ps_cache_filename, ps_inserter);

	ShaderCacheInserter<VertexShaderUid, VsBytecodeCache, &vs_bytecode_cache> vs_inserter;
	s_vs_disk_cache.OpenAndRead(vs_cache_filename, vs_inserter);

	// Clear out disk cache when debugging shaders to ensure stale ones don't stick around..
	SETSTAT(stats.numGeometryShadersAlive, static_cast<int>(gs_bytecode_cache->size()));
	SETSTAT(stats.numGeometryShadersCreated, 0);
	SETSTAT(stats.numPixelShadersAlive, static_cast<int>(ps_bytecode_cache->size()));
	SETSTAT(stats.numPixelShadersCreated, 0);
	SETSTAT(stats.numVertexShadersAlive, static_cast<int>(vs_bytecode_cache->size()));
	SETSTAT(stats.numVertexShadersCreated, 0);
	if (g_ActiveConfig.bCompileShaderOnStartup)
	{
		size_t shader_count = 0;
		ps_bytecode_cache->ForEachMostUsedByCategory(gameid,
			[&](const PixelShaderUid& it, size_t total)
		{
			PixelShaderUid item = it;
			item.ClearHASH();
			item.CalculateUIDHash();
			HandlePSUIDChange(item, true);
			shader_count++;
			if ((shader_count & 7) == 0)
			{
				Host_UpdateTitle(StringFromFormat("Compiling Pixel Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total));
				s_compiler->WaitForFinish();
			}
		},
			[](ByteCodeCacheEntry& entry)
		{
			return !entry.m_shader_bytecode.pShaderBytecode;
		}
		, true);
		shader_count = 0;
		vs_bytecode_cache->ForEachMostUsedByCategory(gameid,
			[&](const VertexShaderUid& it, size_t total)
		{
			VertexShaderUid item = it;
			item.ClearHASH();
			item.CalculateUIDHash();
			HandleVSUIDChange(item, true);
			shader_count++;
			if ((shader_count & 31) == 0)
			{
				Host_UpdateTitle(StringFromFormat("Compiling Vertex Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total));
				s_compiler->WaitForFinish();
			}
		},
			[](ByteCodeCacheEntry& entry)
		{
			return !entry.m_shader_bytecode.pShaderBytecode;
		}
		, true);
		shader_count = 0;
		gs_bytecode_cache->ForEachMostUsedByCategory(gameid,
			[&](const GeometryShaderUid& it, size_t total)
		{
			GeometryShaderUid item = it;
			item.ClearHASH();
			item.CalculateUIDHash();
			HandleGSUIDChange(item, true);
			shader_count++;
			if ((shader_count & 7) == 0)
			{
				Host_UpdateTitle(StringFromFormat("Compiling Geometry Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total));
				s_compiler->WaitForFinish();
			}
		},
			[](ByteCodeCacheEntry& entry)
		{
			return !entry.m_shader_bytecode.pShaderBytecode;
		}
		, true);
		shader_count = 0;
		ts_bytecode_cache->ForEachMostUsedByCategory(gameid,
			[&](const TessellationShaderUid& it, size_t total)
		{
			TessellationShaderUid item = it;
			item.ClearHASH();
			item.CalculateUIDHash();
			HandleTSUIDChange(item, true);
			shader_count++;
			if ((shader_count & 31) == 0)
			{
				Host_UpdateTitle(StringFromFormat("Compiling Tessellation Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total));
				s_compiler->WaitForFinish();
			}
		},
			[](std::pair<ByteCodeCacheEntry, ByteCodeCacheEntry>& entry)
		{
			return !entry.first.m_shader_bytecode.pShaderBytecode;
		}
		, true);
		s_compiler->WaitForFinish();
	}
}
Example #2
0
void PixelShaderCache::Init()
{
	s_pixel_shaders_lock.unlock();
	for (u32 i = 0; i < PSRM_DEPTH_ONLY + 1; i++)
	{
		s_last_entry[i] = nullptr;
	}
	s_compiler = &HLSLAsyncCompiler::getInstance();

	//program used for clear screen
	{
		char pprog[3072];
		sprintf(pprog, "void main(\n"
			"out float4 ocol0 : COLOR0,\n"
			" in float4 incol0 : COLOR0){\n"
			"ocol0 = incol0;\n"
			"}\n");
		s_clear_program = D3D::CompileAndCreatePixelShader(pprog, (int)strlen(pprog));
	}

	int shaderModel = ((D3D::GetCaps().PixelShaderVersion >> 8) & 0xFF);
	int maxConstants = (shaderModel < 3) ? 32 : ((shaderModel < 4) ? 224 : 65536);

	// other screen copy/convert programs
	for (int copyMatrixType = 0; copyMatrixType < NUM_COPY_TYPES; copyMatrixType++)
	{
		for (int depthType = 0; depthType < NUM_DEPTH_CONVERSION_TYPES; depthType++)
		{
			for (int ssaaMode = 0; ssaaMode < MAX_SSAA_SHADERS; ssaaMode++)
			{
				if (ssaaMode && !s_copy_program[copyMatrixType][depthType][ssaaMode - 1]
					|| depthType && !s_copy_program[copyMatrixType][depthType - 1][ssaaMode]
					|| copyMatrixType && !s_copy_program[copyMatrixType - 1][depthType][ssaaMode])
				{
					// if it failed at a lower setting, it's going to fail here for the same reason it did there,
					// so skip this attempt to avoid duplicate error messages.
					s_copy_program[copyMatrixType][depthType][ssaaMode] = NULL;
				}
				else
				{
					s_copy_program[copyMatrixType][depthType][ssaaMode] = CreateCopyShader(copyMatrixType, depthType, ssaaMode);
				}
			}
		}
	}

	Clear();

	if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
		File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX).c_str());

	SETSTAT(stats.numPixelShadersCreated, 0);
	SETSTAT(stats.numPixelShadersAlive, 0);

	pKey_t gameid = (pKey_t)GetMurmurHash3(reinterpret_cast<const u8*>(SConfig::GetInstance().m_strGameID.data()), (u32)SConfig::GetInstance().m_strGameID.size(), 0);
	s_pshaders = ObjectUsageProfiler<PixelShaderUid, pKey_t, PSCacheEntry, PixelShaderUid::ShaderUidHasher>::Create(
		gameid,
		PIXELSHADERGEN_UID_VERSION,
		"Ishiiruka.ps.dx9",
		StringFromFormat("%s.ps.dx9", SConfig::GetInstance().m_strGameID.c_str())
	);

	std::string cache_filename = StringFromFormat("%sIDX9-%s-ps.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
		SConfig::GetInstance().m_strGameID.c_str());

	PixelShaderCacheInserter inserter;
	g_ps_disk_cache.OpenAndRead(cache_filename, inserter);

	if (g_ActiveConfig.bCompileShaderOnStartup)
	{
		std::vector<PixelShaderUid> shaders;
		size_t shader_count = 0;
		s_pshaders->ForEachMostUsedByCategory(gameid,
			[&](const PixelShaderUid& item, size_t total)
		{
			PixelShaderUid newitem = item;
			pixel_shader_uid_data& uid_data = newitem.GetUidData<pixel_shader_uid_data>();

			if (uid_data.render_mode == PSRM_DUAL_SOURCE_BLEND && !g_ActiveConfig.backend_info.bSupportsDualSourceBlend)
			{
				uid_data.render_mode = PSRM_DEFAULT;
				newitem.ClearHASH();
				newitem.CalculateUIDHash();
				CompilePShader(newitem, PIXEL_SHADER_RENDER_MODE::PSRM_DEFAULT, true);
				uid_data.render_mode = PSRM_ALPHA_PASS;
				uid_data.fog_proj = 0;
				uid_data.fog_RangeBaseEnabled = 0;
				newitem.ClearHASH();
				newitem.CalculateUIDHash();
				CompilePShader(newitem, PIXEL_SHADER_RENDER_MODE::PSRM_ALPHA_PASS, true);
			}
			else
			{
				newitem.ClearHASH();
				newitem.CalculateUIDHash();
				CompilePShader(newitem, PIXEL_SHADER_RENDER_MODE::PSRM_DEFAULT, true);
			}
			shader_count++;
			if ((shader_count & 7) == 0)
			{
				Host_UpdateTitle(StringFromFormat("Compiling Pixel Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total));
				s_compiler->WaitForFinish();
			}
		},
			[](PSCacheEntry& entry)
		{
			return !entry.shader;
		}, true);
		s_compiler->WaitForFinish();
	}
}
Example #3
0
})hlsl";


void VertexShaderCache::Init()
{
	s_vshaders_lock.unlock();
	s_compiler = &HLSLAsyncCompiler::getInstance();
	const D3D11_INPUT_ELEMENT_DESC simpleelems[3] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 1, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 }
	};
	const D3D11_INPUT_ELEMENT_DESC clearelems[2] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};

	bool use_partial_buffer_update = D3D::SupportPartialContantBufferUpdate();
	u32 cbsize = VertexShaderManager::ConstantBufferSize * sizeof(float) * (use_partial_buffer_update ? 1024 : 1); // is always multiple of 16
	vscbuf = new D3D::ConstantStreamBuffer(cbsize);
	ID3D11Buffer* buf = vscbuf->GetBuffer();

	CHECK(buf != nullptr, "Create vertex shader constant buffer (size=%u)", cbsize);
	D3D::SetDebugObjectName(buf, "vertex shader constant buffer used to emulate the GX pipeline");

	D3DBlob blob;
	D3D::CompileShader(D3D::ShaderType::Vertex, simple_shader_code, blob);
	D3D::device->CreateInputLayout(simpleelems, 3, blob.Data(), blob.Size(), D3D::ToAddr(s_simple_layout));
	s_simple_vertex_shader = D3D::CreateVertexShaderFromByteCode(blob);
	if (s_simple_layout == nullptr ||
		s_simple_vertex_shader == nullptr)
		PanicAlert("Failed to create simple vertex shader or input layout at %s %d\n", __FILE__, __LINE__);

	D3D::SetDebugObjectName(s_simple_layout.get(), "simple input layout");
	D3D::SetDebugObjectName(s_simple_vertex_shader.get(), "simple vertex shader");

	D3D::CompileShader(D3D::ShaderType::Vertex, clear_shader_code, blob);
	D3D::device->CreateInputLayout(clearelems, 2, blob.Data(), blob.Size(), D3D::ToAddr(s_clear_layout));
	s_clear_vertex_shader = D3D::CreateVertexShaderFromByteCode(blob);
	if (s_clear_layout == nullptr ||
		s_clear_vertex_shader == nullptr)
		PanicAlert("Failed to create clear vertex shader or input layout at %s %d\n", __FILE__, __LINE__);
	D3D::SetDebugObjectName(s_clear_vertex_shader.get(), "clear vertex shader");
	D3D::SetDebugObjectName(s_clear_layout.get(), "clear input layout");

	Clear();

	if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
		File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX).c_str());

	SETSTAT(stats.numVertexShadersCreated, 0);
	SETSTAT(stats.numVertexShadersAlive, 0);

	pKey_t gameid = (pKey_t)GetMurmurHash3(reinterpret_cast<const u8*>(SConfig::GetInstance().m_strGameID.data()), (u32)SConfig::GetInstance().m_strGameID.size(), 0);
	s_vshaders = VSCache::Create(
		gameid,
		VERTEXSHADERGEN_UID_VERSION,
		"Ishiiruka.vs",
		StringFromFormat("%s.vs", SConfig::GetInstance().m_strGameID.c_str())
	);

	std::string cache_filename = StringFromFormat("%sIDX11-%s-vs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
		SConfig::GetInstance().m_strGameID.c_str());

	VertexShaderCacheInserter inserter;
	g_vs_disk_cache.OpenAndRead(cache_filename, inserter);
	if (g_ActiveConfig.bCompileShaderOnStartup)
	{
		size_t shader_count = 0;
		s_vshaders->ForEachMostUsedByCategory(gameid,
			[&](const VertexShaderUid& it, size_t total)
		{
			VertexShaderUid item = it;
			item.ClearHASH();
			item.CalculateUIDHash();
			CompileVShader(item, true);
			shader_count++;
			if ((shader_count & 7) == 0)
			{
				Host_UpdateTitle(StringFromFormat("Compiling Vertex Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total));
				s_compiler->WaitForFinish();
			}
		},
			[](VSCacheEntry& entry)
		{
			return !entry.shader;
		}
		, true);
		s_compiler->WaitForFinish();
	}
	s_last_entry = nullptr;
}
Example #4
0
)hlsl";

void GeometryShaderCache::Init()
{
	s_compiler = &HLSLAsyncCompiler::getInstance();
	s_geometry_shaders_lock.unlock();
	bool use_partial_buffer_update = D3D::SupportPartialContantBufferUpdate();
	u32 gbsize = static_cast<u32>(Common::AlignUpSizePow2(sizeof(GeometryShaderConstants), 16) * (use_partial_buffer_update ? 1024 : 1)); // must be a multiple of 16
	gscbuf = new D3D::ConstantStreamBuffer(gbsize);
	ID3D11Buffer* buf = gscbuf->GetBuffer();
	CHECK(buf != nullptr, "Create geometry shader constant buffer (size=%u)", gbsize);
	D3D::SetDebugObjectName(buf, "geometry shader constant buffer used to emulate the GX pipeline");

	// used when drawing clear quads
	ClearGeometryShader = D3D::CompileAndCreateGeometryShader(gs_clear_shader_code);
	CHECK(ClearGeometryShader != nullptr, "Create clear geometry shader");
	D3D::SetDebugObjectName(ClearGeometryShader.get(), "clear geometry shader");

	// used for buffer copy
	CopyGeometryShader = D3D::CompileAndCreateGeometryShader(gs_copy_shader_code);
	CHECK(CopyGeometryShader != nullptr, "Create copy geometry shader");
	D3D::SetDebugObjectName(CopyGeometryShader.get(), "copy geometry shader");

	Clear();

	if (!File::Exists(File::GetUserPath(D_SHADERCACHE_IDX)))
		File::CreateDir(File::GetUserPath(D_SHADERCACHE_IDX));

	pKey_t gameid = (pKey_t)GetMurmurHash3(reinterpret_cast<const u8*>(SConfig::GetInstance().m_strGameID.data()), (u32)SConfig::GetInstance().m_strGameID.size(), 0);
	s_geometry_shaders = GSCache::Create(
		gameid,
		GEOMETRYSHADERGEN_UID_VERSION,
		"Ishiiruka.gs",
		StringFromFormat("%s.gs", SConfig::GetInstance().m_strGameID.c_str())
	);

	std::string cache_filename = StringFromFormat("%sIDX11-%s-gs.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
		SConfig::GetInstance().m_strGameID.c_str());
	GeometryShaderCacheInserter inserter;
	g_gs_disk_cache.OpenAndRead(cache_filename, inserter);

	if (g_ActiveConfig.bCompileShaderOnStartup)
	{
		size_t shader_count = 0;
		s_geometry_shaders->ForEachMostUsedByCategory(gameid,
			[&](const GeometryShaderUid& it, size_t total)
		{
			GeometryShaderUid item = it;
			item.ClearHASH();
			item.CalculateUIDHash();
			CompileGShader(item, true);
			shader_count++;
			if ((shader_count & 7) == 0)
			{
				Host_UpdateTitle(StringFromFormat("Compiling Geometry Shaders %i %% (%i/%i)", (shader_count * 100) / total, shader_count, total));
				s_compiler->WaitForFinish();
			}
		},
			[](GSCacheEntry& entry)
		{
			return !entry.shader;
		}
		, true);
		s_compiler->WaitForFinish();
	}

	s_last_entry = nullptr;
}