mirror of
				https://github.com/dolphin-emu/dolphin.git
				synced 2025-10-25 01:19:19 +00:00 
			
		
		
		
	Reason: - It's wrong, zcomploc can't be emulated perfectly in HW backends without severely impacting performance. - It provides virtually no advantages over the previous hack while introducing lots of code. - There is a better alternative: If people insist on having some sort of valid zcomploc emulation, I suggest rendering each primitive separately while using a _clean_ dual-pass approach to emulate zcomploc. This reverts commit0efd4e5c29. This reverts commitb4ec836aca. This reverts commitbb4c9e2205. This reverts commit146b02615c.
		
			
				
	
	
		
			204 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (C) 2003 Dolphin Project.
 | |
| 
 | |
| // This program is free software: you can redistribute it and/or modify
 | |
| // it under the terms of the GNU General Public License as published by
 | |
| // the Free Software Foundation, version 2.0.
 | |
| 
 | |
| // This program is distributed in the hope that it will be useful,
 | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| // GNU General Public License 2.0 for more details.
 | |
| 
 | |
| // A copy of the GPL 2.0 should have been included with the program.
 | |
| // If not, see http://www.gnu.org/licenses/
 | |
| 
 | |
| // Official SVN repository and contact information can be found at
 | |
| // http://code.google.com/p/dolphin-emu/
 | |
| 
 | |
| #ifndef _LINEAR_DISKCACHE
 | |
| #define _LINEAR_DISKCACHE
 | |
| 
 | |
| #include "Common.h"
 | |
| #include <fstream>
 | |
| 
 | |
| // Increment this every time you change shader generation code.
 | |
| enum
 | |
| {
 | |
| 	LINEAR_DISKCACHE_VER = 6975
 | |
| };
 | |
| 
 | |
| // On disk format:
 | |
| //header{
 | |
| // u32 'DCAC';
 | |
| // u32 version;  // svn_rev
 | |
| // u16 sizeof(key_type);
 | |
| // u16 sizeof(value_type);
 | |
| //}
 | |
| 
 | |
| //key_value_pair{
 | |
| // u32 value_size;
 | |
| // key_type   key;
 | |
| // value_type[value_size]   value;
 | |
| //}
 | |
| 
 | |
| template <typename K, typename V>
 | |
| class LinearDiskCacheReader
 | |
| {
 | |
| public:
 | |
| 	virtual void Read(const K &key, const V *value, u32 value_size) = 0;
 | |
| };
 | |
| 
 | |
| // Dead simple unsorted key-value store with append functionality.
 | |
| // No random read functionality, all reading is done in OpenAndRead.
 | |
| // Keys and values can contain any characters, including \0.
 | |
| //
 | |
| // Suitable for caching generated shader bytecode between executions.
 | |
| // Not tuned for extreme performance but should be reasonably fast.
 | |
| // Does not support keys or values larger than 2GB, which should be reasonable.
 | |
| // Keys must have non-zero length; values can have zero length.
 | |
| 
 | |
| // K and V are some POD type
 | |
| // K : the key type
 | |
| // V : value array type
 | |
| template <typename K, typename V>
 | |
| class LinearDiskCache
 | |
| {
 | |
| public:
 | |
| 	// return number of read entries
 | |
| 	u32 OpenAndRead(const char *filename, LinearDiskCacheReader<K, V> &reader)
 | |
| 	{
 | |
| 		using std::ios_base;
 | |
| 
 | |
| 		// close any currently opened file
 | |
| 		Close();
 | |
| 		m_num_entries = 0;
 | |
| 
 | |
| 		// try opening for reading/writing
 | |
| 		m_file.open(filename, ios_base::in | ios_base::out | ios_base::binary);
 | |
| 
 | |
| 		m_file.seekg(0, std::ios::end);
 | |
| 		std::fstream::pos_type end_pos = m_file.tellg();
 | |
| 		m_file.seekg(0, std::ios::beg);
 | |
| 		std::fstream::pos_type start_pos = m_file.tellg();
 | |
| 		std::streamoff file_size = end_pos - start_pos;
 | |
| 		
 | |
| 		if (m_file.is_open() && ValidateHeader())
 | |
| 		{
 | |
| 			// good header, read some key/value pairs
 | |
| 			K key;
 | |
| 
 | |
| 			V *value = NULL;
 | |
| 			u32 value_size;
 | |
| 			u32 entry_number;
 | |
| 
 | |
| 			std::fstream::pos_type last_pos = m_file.tellg();
 | |
| 
 | |
| 			while (Read(&value_size))
 | |
| 			{
 | |
| 				std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size;
 | |
| 				if (next_extent > file_size)
 | |
| 					break;
 | |
| 
 | |
| 				delete[] value;
 | |
| 				value = new V[value_size];
 | |
| 
 | |
| 				// read key/value and pass to reader
 | |
| 				if (Read(&key) &&
 | |
| 					Read(value, value_size) && 
 | |
| 					Read(&entry_number) &&
 | |
| 					entry_number == m_num_entries+1)
 | |
|  				{
 | |
| 					reader.Read(key, value, value_size);
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					break;
 | |
| 				}
 | |
| 
 | |
| 				m_num_entries++;
 | |
| 				last_pos = m_file.tellg();
 | |
| 			}
 | |
| 			m_file.seekp(last_pos);
 | |
| 			m_file.clear();
 | |
| 
 | |
| 			delete[] value;
 | |
| 			return m_num_entries;
 | |
| 		}
 | |
| 
 | |
| 		// failed to open file for reading or bad header
 | |
| 		// close and recreate file
 | |
| 		Close();
 | |
| 		m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary);
 | |
| 		WriteHeader();
 | |
| 		return 0;
 | |
| 	}
 | |
| 	
 | |
| 	void Sync()
 | |
| 	{
 | |
| 		m_file.flush();
 | |
| 	}
 | |
| 
 | |
| 	void Close()
 | |
| 	{
 | |
| 		if (m_file.is_open())
 | |
| 			m_file.close();
 | |
| 		// clear any error flags
 | |
| 		m_file.clear();
 | |
| 	}
 | |
| 
 | |
| 	// Appends a key-value pair to the store.
 | |
| 	void Append(const K &key, const V *value, u32 value_size)
 | |
| 	{
 | |
| 		// TODO: Should do a check that we don't already have "key"? (I think each caller does that already.)
 | |
| 		Write(&value_size);
 | |
| 		Write(&key);
 | |
| 		Write(value, value_size);
 | |
| 		m_num_entries++;
 | |
| 		Write(&m_num_entries);
 | |
| 	}
 | |
| 
 | |
| private:
 | |
| 	void WriteHeader()
 | |
| 	{
 | |
| 		Write(&m_header);
 | |
| 	}
 | |
| 
 | |
| 	bool ValidateHeader()
 | |
| 	{
 | |
| 		char file_header[sizeof(Header)];
 | |
| 
 | |
| 		return (Read(file_header, sizeof(Header))
 | |
| 			&& !memcmp((const char*)&m_header, file_header, sizeof(Header)));
 | |
| 	}
 | |
| 
 | |
| 	template <typename D>
 | |
| 	bool Write(const D *data, u32 count = 1)
 | |
| 	{
 | |
| 		return m_file.write((const char*)data, count * sizeof(D)).good();
 | |
| 	}
 | |
| 
 | |
| 	template <typename D>
 | |
| 	bool Read(const D *data, u32 count = 1)
 | |
| 	{
 | |
| 		return m_file.read((char*)data, count * sizeof(D)).good();
 | |
| 	}
 | |
| 
 | |
| 	struct Header
 | |
| 	{
 | |
| 		Header()
 | |
| 			: id(*(u32*)"DCAC")
 | |
| 			, ver(LINEAR_DISKCACHE_VER)
 | |
| 			, key_t_size(sizeof(K))
 | |
| 			, value_t_size(sizeof(V))
 | |
| 		{}
 | |
| 
 | |
| 		const u32 id, ver;
 | |
| 		const u16 key_t_size, value_t_size;
 | |
| 
 | |
| 	} m_header;
 | |
| 
 | |
| 	std::fstream m_file;
 | |
| 	u32 m_num_entries;
 | |
| };
 | |
| 
 | |
| #endif  // _LINEAR_DISKCACHE
 |