예제 #1
0
TechniqueToon::~TechniqueToon()
{
    //Delete the color schemes loaded during
    //initialization.
    FreeTexture(mLookups[0]);
    FreeTexture(mLookups[1]);
    FreeTexture(mLookups[2]);
}
예제 #2
0
void TextureCache::Cleanup(int _frameCount)
{
	TexCache::iterator iter = textures_by_address.begin();
	TexCache::iterator tcend = textures_by_address.end();
	while (iter != tcend)
	{
		if (iter->second->frameCount == FRAMECOUNT_INVALID)
		{
			iter->second->frameCount = _frameCount;
			++iter;
		}
		else if (_frameCount > TEXTURE_KILL_THRESHOLD + iter->second->frameCount)
		{
			if (iter->second->IsEfbCopy())
			{
				// Only remove EFB copies when they wouldn't be used anymore(changed hash), because EFB copies living on the
				// host GPU are unrecoverable. Perform this check only every TEXTURE_KILL_THRESHOLD for performance reasons
				if ((_frameCount - iter->second->frameCount) % TEXTURE_KILL_THRESHOLD == 1 &&
					iter->second->hash != iter->second->CalculateHash())
				{
					iter = FreeTexture(iter);
				}
				else
				{
					++iter;
				}
			}
			else
			{
				iter = FreeTexture(iter);
			}
		}
		else
		{
			++iter;
		}
	}

	TexPool::iterator iter2 = texture_pool.begin();
	TexPool::iterator tcend2 = texture_pool.end();
	while (iter2 != tcend2)
	{
		if (iter2->second->frameCount == FRAMECOUNT_INVALID)
		{
			iter2->second->frameCount = _frameCount;
		}
		if (_frameCount > TEXTURE_POOL_KILL_THRESHOLD + iter2->second->frameCount)
		{
			delete iter2->second;
			iter2 = texture_pool.erase(iter2);
		}
		else
		{
			++iter2;
		}
	}
}
예제 #3
0
		void Chowdren::LoadTexture( Gwen::Texture* pTexture )
		{
            pTexture->failed = true;
            return;

            if (pTexture->data)
                FreeTexture(pTexture);

            pTexture->data = (void*)new FileImage(pTexture->name.c_str(), 0, 0,
                0, 0, TransparentColor());

            if (((FileImage*)pTexture->data)->tex == 0) {
                pTexture->failed = true;
                FreeTexture(pTexture);
            }
		}
예제 #4
0
void Texture::InitializeBuffer( unsigned int nWidth, unsigned int nHeight, 
							    const std::vector<unsigned char> & vBuffer,
								unsigned int nGLTextureFormat )
{
	FreeTexture();

	m_nWidth = nWidth;
	m_nHeight = nHeight;
	m_vBuffer = vBuffer;

	//  figure out scaling factors
	m_nTexWidth = 1;
	while ( m_nTexWidth < nWidth )
		m_nTexWidth *= 2;
	float fScaleX = (float)m_nTexWidth / (float)nWidth;
	m_nTexHeight = 1;
	while ( m_nTexHeight < nHeight )
		m_nTexHeight *= 2;
	float fScaleY = (float)m_nTexHeight / (float)nHeight;
	m_fScaleX = (fScaleX < fScaleY) ? fScaleX : fScaleY;
	m_fScaleX = 1.0f / m_fScaleX;	// scale tex coords *down* to scale image *up*

	lgASSERT( (unsigned int)vBuffer.size() % (nWidth * nHeight) == 0 );
	m_nComponents = (unsigned int)vBuffer.size() / (nWidth * nHeight);

	m_nGLTextureFormat = nGLTextureFormat;
}
예제 #5
0
        void SDL2Renderer::LoadTexture(Gwen::Texture* pTexture)
        {
            if (!pTexture)
                return;

            if (pTexture->data)
                FreeTexture(pTexture);
            
            SDL_Texture *tex = NULL;
            // Don't need to read. Just load straight into render format.
            tex = IMG_LoadTexture(m_renderer, pTexture->name.c_str());

            if (tex)
            {
                int w, h;
                SDL_QueryTexture(tex, NULL, NULL, &w, &h);
                
                pTexture->data = tex;
                pTexture->width = w;
                pTexture->height = h;
                pTexture->failed = false;
            }
            else
            {
                pTexture->data = NULL;
                pTexture->failed = true;
            }
        }
예제 #6
0
int CTextureManager::GetNewTextureID (int nPossibleTextureID) {

	// First check if the possible textureID has already been
	// used, however the default value is -1, err that is what
	// this method is passed from LoadTexture ()
	if (nPossibleTextureID != -1) {
		for (int i = 0; i < m_Singleton->nAvailable; i++) {
			if (m_Singleton->nTexIDs [i] == nPossibleTextureID) {
				FreeTexture (nPossibleTextureID);	// sets nTexIDs [i] to -1...
				m_Singleton->nNumTextures--;		// since we will add the ID again...
				break;
			}
		}
	}

	// Actually look for a new one
	int nNewTextureID;
	if (nPossibleTextureID == -1) {
		unsigned int nGLID;	
		glGenTextures (1, &nGLID);
		nNewTextureID = (int) nGLID;
	}
	else	// If the user is handle the textureIDs
		nNewTextureID = nPossibleTextureID;
	
	// find an empty slot in the TexID array
	int nIndex = 0;
	while (m_Singleton->nTexIDs [nIndex] != -1 && nIndex < m_Singleton->nAvailable)
		nIndex++;

	// all space exaused, make MORE!
	if (nIndex >= m_Singleton->nAvailable) {
		int *pNewIDs = new int [m_Singleton->nAvailable + TEXTURE_STEP];
		int i;
		
		// copy the old
		for (i = 0; i < m_Singleton->nAvailable; i++)
			pNewIDs [i] = m_Singleton->nTexIDs [i];
		// set the last increment to the newest ID
		pNewIDs [m_Singleton->nAvailable] = nNewTextureID;
		// set the new to '-1'
		for (i = 1; i < TEXTURE_STEP; i++)
			pNewIDs [i + m_Singleton->nAvailable] = -1;

		m_Singleton->nAvailable += TEXTURE_STEP;
		delete [] m_Singleton->nTexIDs;
		m_Singleton->nTexIDs = pNewIDs;
	}
	else
		m_Singleton->nTexIDs [nIndex] = nNewTextureID;

	// Welcome to our Texture Array!
	m_Singleton->nNumTextures++;
	return nNewTextureID;
}
예제 #7
0
// free all textures
void FreeTextures(void)
{
	// TODO: Медленно же!!111
	for(;;)
	{
		if(texture_count > 0)
			FreeTexture(&textures[texture_count-1]);
		else
			break;
	}
}
예제 #8
0
void TextureCacheBase::Invalidate()
{
	UnbindTextures();
	TexCache::iterator iter = textures_by_address.begin();
	TexCache::iterator end = textures_by_address.end();
	while (iter != end)
	{
		iter = FreeTexture(iter);
	}
	textures_by_address.clear();
	textures_by_hash.clear();
}
예제 #9
0
/*
    Function: Main entry point ( Application main )

    Flow:
        - Init GLUT
        - Setup Window Buffers ( Double render buffer as well as support
            for Alpha, and Depth buffer)
        - Setup Window Width, Height, X, Y Position
        - Create Window with title
        - Setup Lighting
        - Set callback to display function for rendering
        - Set callback to reshape function for changing the size of the viewport
        - Set callback to keyPressed and keyUp to handle keyboard input
        - Tell GLUT to enter main loop
            E.g
                while( running ) {
                    doApplicationStuff();
                }
    End State:
        Creation and running of an application as well as closing and
        releasing all resources used by the application
*/
int main(int argc, char **argv)
{
    int windowWidth     = 500;
    int windowHeight    = 500;
    int windowXPos      = 100;
    int windowYPos      = 100;

    // Initialize GLUT with command line input
    glutInit(&argc, argv);

    // Set up a basic buffer (only single buffered for now)
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);

	glutGameModeString("1440x900:32@60");
	glutEnterGameMode();

    // Set width ,height, X Pos and Y pos of window
    //glutInitWindowSize(windowWidth, windowHeight);
    //glutInitWindowPosition(windowXPos, windowYPos);

    // Create window with title
    //glutCreateWindow("Basic Window with lighting!");

    // Clear keyboard state
    initKeyboardState();

    // Setup lighting
    initLighting();

	 // Initiate object lists
	 CreateCube();

    // Setup Idle and Display to both use the 'display' function,
    // set the reshape event to use the 'reshape' funciton
    glutDisplayFunc(display);
    glutIdleFunc(display);
    glutReshapeFunc(reshape);

    // Set keyboard callback function to handle key pressing and releasing
    glutKeyboardFunc(keyPressed);
    glutKeyboardUpFunc(keyUp);
    glutSpecialFunc(keySpecialPressed);
    glutSpecialUpFunc(keySpecialUp);
    
    // Run the main loop which will handle closing of the application
	 glutMainLoop();

    // Free the texture
    FreeTexture( texture );
}
예제 #10
0
파일: texcache.cpp 프로젝트: joeriedel/Crow
static void FreeAllTextures(void)
{
	int i;
	TC_Texture_t *WorkPtr;
	WorkPtr = c_textures;
	i = MAX_CACHED_TEXTURES;
	do {
		if (WorkPtr->used) {		/* Is this used? */
			FreeTexture(WorkPtr);	/* Zap this texture */
		}
		++WorkPtr;					/* Continue traversal */
	} while (--i);
	c_num_textures = 0;
}
예제 #11
0
파일: SFML2.cpp 프로젝트: jjiezheng/lfant
void Gwen::Renderer::SFML2::LoadTexture( Gwen::Texture* pTexture )
{
	if ( !pTexture ) return;
	if ( pTexture->data ) FreeTexture( pTexture );

	sf::Texture* tex = new sf::Texture();
	tex->setSmooth( true );
	if ( !tex->loadFromFile( pTexture->name.Get() ) )
	{
		delete( tex );
		pTexture->failed = true;
		return;
	}

	pTexture->height = tex->getSize().x;
	pTexture->width = tex->getSize().y;
	pTexture->data = new TextureData( tex );
}
예제 #12
0
파일: ClanLib.cpp 프로젝트: Kezeali/Fusion
		void ClanLib::LoadTexture( Gwen::Texture* pTexture )
		{
			if ( !pTexture ) { return; }
			if ( pTexture->data ) { FreeTexture( pTexture ); }

			clan::Image* tex = new clan::Image(m_Target, pTexture->name.Get(), m_FileSystem);
			//tex->SetSmooth( true );

			//if ( !tex->LoadFromFile( pTexture->name.Get() ) )
			if (tex->is_null())
			{
				delete( tex );
				pTexture->failed = true;
				return;
			}
			
			pTexture->height = tex->get_height();
			pTexture->width = tex->get_width();
			pTexture->data = new TextureData( tex );
			
		};
예제 #13
0
파일: SDL2.cpp 프로젝트: craley/Poky
        void SDL2::LoadTexture(Gwen::Texture* pTexture)
        {
            if (!pTexture)
                return;

            if (pTexture->data)
                FreeTexture(pTexture);
            
            SDL_Texture *tex = NULL;
            if (pTexture->readable)
            {
                // You cannot find the format of a texture once loaded to read from it
                // in SDL2 so we have to keep the surface to read from.
                SDL_Surface *surf = IMG_Load(pTexture->name.c_str());
                tex = SDL_CreateTextureFromSurface(m_renderer, surf);
                pTexture->surface = surf;
            }
            else
            {
                // Don't need to read. Just load straight into render format.
                tex = IMG_LoadTexture(m_renderer, pTexture->name.c_str());
            }

            if (tex)
            {
                int w, h;
                SDL_QueryTexture(tex, NULL, NULL, &w, &h);
                
                pTexture->data = tex;
                pTexture->width = w;
                pTexture->height = h;
                pTexture->failed = false;
            }
            else
            {
                pTexture->data = NULL;
                pTexture->failed = true;
            }
        }
예제 #14
0
/**
* Texture wrapper class
* @return bool
* @param  fileName The file path of the image
*/
bool Texture::LoadFromFile (std::string fileName )
{
	//Clean up first
	FreeTexture();

	//The final texture
	SDL_Texture* newTexture = NULL;

	//Load image at specified path
	SDL_Surface* loadedSurface = IMG_Load( fileName.c_str() );
	if( loadedSurface == NULL )
	{
		printf( "Unable to load image %s! SDL_image Error: %s\n", fileName.c_str(), IMG_GetError() );
	}
	else
	{
		//Create texture from surface pixels
        newTexture = SDL_CreateTextureFromSurface( ResourceManager::getResourceManager().GetGlobalRenderer(),
												   loadedSurface );
		if( newTexture == NULL )
		{
			printf( "Unable to create texture from %s! SDL Error: %s\n", fileName.c_str(), SDL_GetError() );
		}
		else
		{
			//Get image dimensions
			mWidth = loadedSurface->w;
			mHeight = loadedSurface->h;
		}

		//Get rid of old loaded surface
		SDL_FreeSurface( loadedSurface );
	}

	//Return success
	mTexture = newTexture;
	return mTexture != NULL;
}
예제 #15
0
int main(int argc, char **argv)
{

    glutInit(&argc, argv); // Initializes glut

    // Sets up a double buffer with RGBA components and a depth component
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA);

    // Sets the window size to 512*512 square pixels
    glutInitWindowSize(512, 512);

    // Sets the window position to the upper left
    glutInitWindowPosition(0, 0);

    // Creates a window using internal glut functionality
    glutCreateWindow("Hello!");

    // passes reshape and display functions to the OpenGL machine for callback
//	glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutIdleFunc(display);

    init();

    g_texture = LoadTextureRAW("texture.raw", true);
    if (!g_texture)
    {
        printf("texture load error!\n");
        return -1;
    }

    // Starts the program.
    glutMainLoop();

    FreeTexture(g_texture);
    return 0;
}
예제 #16
0
파일: SFML.cpp 프로젝트: dabroz/gwen-mirror
		void SFML::LoadTexture( Gwen::Texture* pTexture )
		{
			if ( !pTexture ) return;
			if ( pTexture->data ) FreeTexture( pTexture );

#if SFML_VERSION_MAJOR == 2
			sf::Texture* tex = new sf::Texture();
#else
			sf::Image* tex = new sf::Image();
#endif
			tex->SetSmooth( true );

			if ( !tex->LoadFromFile( pTexture->name.Get() ) )
			{
				delete( tex );
				pTexture->failed = true;
				return;
			}

			pTexture->height = tex->GetHeight();
			pTexture->width = tex->GetWidth();
			pTexture->data = tex;

		};
예제 #17
0
TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
{
	const FourTexUnits &tex = bpmem.tex[stage >> 2];
	const u32 id = stage & 3;
	const u32 address = (tex.texImage3[id].image_base/* & 0x1FFFFF*/) << 5;
	u32 width = tex.texImage0[id].width + 1;
	u32 height = tex.texImage0[id].height + 1;
	const int texformat = tex.texImage0[id].format;
	const u32 tlutaddr = tex.texTlut[id].tmem_offset << 9;
	const u32 tlutfmt = tex.texTlut[id].tlut_format;
	const bool use_mipmaps = (tex.texMode0[id].min_filter & 3) != 0;
	u32 tex_levels = use_mipmaps ? ((tex.texMode1[id].max_lod + 0xf) / 0x10 + 1) : 1;
	const bool from_tmem = tex.texImage1[id].image_type != 0;

	if (0 == address)
		return nullptr;

	// TexelSizeInNibbles(format) * width * height / 16;
	const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat);
	const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat);

	unsigned int expandedWidth = ROUND_UP(width, bsw);
	unsigned int expandedHeight = ROUND_UP(height, bsh);
	const unsigned int nativeW = width;
	const unsigned int nativeH = height;

	// Hash assigned to texcache entry (also used to generate filenames used for texture dumping and custom texture lookup)
	u64 base_hash = TEXHASH_INVALID;
	u64 full_hash = TEXHASH_INVALID;

	u32 full_format = texformat;

	const bool isPaletteTexture = (texformat == GX_TF_C4 || texformat == GX_TF_C8 || texformat == GX_TF_C14X2);

	// Reject invalid tlut format.
	if (isPaletteTexture && tlutfmt > GX_TL_RGB5A3)
		return nullptr;

	if (isPaletteTexture)
		full_format = texformat | (tlutfmt << 16);

	const u32 texture_size = TexDecoder_GetTextureSizeInBytes(expandedWidth, expandedHeight, texformat);
	u32 additional_mips_size = 0; // not including level 0, which is texture_size

	// GPUs don't like when the specified mipmap count would require more than one 1x1-sized LOD in the mipmap chain
	// e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,0x0, so we limit the mipmap count to 6 there
	tex_levels = std::min<u32>(IntLog2(std::max(width, height)) + 1, tex_levels);

	for (u32 level = 1; level != tex_levels; ++level)
	{
		// We still need to calculate the original size of the mips
		const u32 expanded_mip_width = ROUND_UP(CalculateLevelSize(width, level), bsw);
		const u32 expanded_mip_height = ROUND_UP(CalculateLevelSize(height, level), bsh);

		additional_mips_size += TexDecoder_GetTextureSizeInBytes(expanded_mip_width, expanded_mip_height, texformat);
	}

	// If we are recording a FifoLog, keep track of what memory we read.
	// FifiRecorder does it's own memory modification tracking independant of the texture hashing below.
	if (g_bRecordFifoData && !from_tmem)
		FifoRecorder::GetInstance().UseMemory(address, texture_size + additional_mips_size, MemoryUpdate::TEXTURE_MAP);

	const u8* src_data;
	if (from_tmem)
		src_data = &texMem[bpmem.tex[stage / 4].texImage1[stage % 4].tmem_even * TMEM_LINE_SIZE];
	else
		src_data = Memory::GetPointer(address);

	// TODO: This doesn't hash GB tiles for preloaded RGBA8 textures (instead, it's hashing more data from the low tmem bank than it should)
	base_hash = GetHash64(src_data, texture_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
	u32 palette_size = 0;
	if (isPaletteTexture)
	{
		palette_size = TexDecoder_GetPaletteSize(texformat);
		full_hash = base_hash ^ GetHash64(&texMem[tlutaddr], palette_size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
	}
	else
	{
		full_hash = base_hash;
	}

	// Search the texture cache for textures by address
	//
	// Find all texture cache entries for the current texture address, and decide whether to use one of
	// them, or to create a new one
	//
	// In most cases, the fastest way is to use only one texture cache entry for the same address. Usually,
	// when a texture changes, the old version of the texture is unlikely to be used again. If there were
	// new cache entries created for normal texture updates, there would be a slowdown due to a huge amount
	// of unused cache entries. Also thanks to texture pooling, overwriting an existing cache entry is
	// faster than creating a new one from scratch.
	//
	// Some games use the same address for different textures though. If the same cache entry was used in
	// this case, it would be constantly overwritten, and effectively there wouldn't be any caching for
	// those textures. Examples for this are Metroid Prime and Castlevania 3. Metroid Prime has multiple
	// sets of fonts on each other stored in a single texture and uses the palette to make different
	// characters visible or invisible. In Castlevania 3 some textures are used for 2 different things or
	// at least in 2 different ways(size 1024x1024 vs 1024x256).
	//
	// To determine whether to use multiple cache entries or a single entry, use the following heuristic:
	// If the same texture address is used several times during the same frame, assume the address is used
	// for different purposes and allow creating an additional cache entry. If there's at least one entry
	// that hasn't been used for the same frame, then overwrite it, in order to keep the cache as small as
	// possible. If the current texture is found in the cache, use that entry.
	//
	// For efb copies, the entry created in CopyRenderTargetToTexture always has to be used, or else it was
	// done in vain.
	std::pair<TexCache::iterator, TexCache::iterator> iter_range = textures_by_address.equal_range((u64)address);
	TexCache::iterator iter = iter_range.first;
	TexCache::iterator oldest_entry = iter;
	int temp_frameCount = 0x7fffffff;
	TexCache::iterator unconverted_copy = textures_by_address.end();

	while (iter != iter_range.second)
	{
		TCacheEntryBase* entry = iter->second;
		// Do not load strided EFB copies, they are not meant to be used directly
		if (entry->IsEfbCopy() && entry->native_width == nativeW && entry->native_height == nativeH &&
			entry->memory_stride == entry->CacheLinesPerRow() * 32)
		{
			// EFB copies have slightly different rules as EFB copy formats have different
			// meanings from texture formats.
			if ((base_hash == entry->hash && (!isPaletteTexture || g_Config.backend_info.bSupportsPaletteConversion)) ||
				IsPlayingBackFifologWithBrokenEFBCopies)
			{
				// TODO: We should check format/width/height/levels for EFB copies. Checking
				// format is complicated because EFB copy formats don't exactly match
				// texture formats. I'm not sure what effect checking width/height/levels
				// would have.
				if (!isPaletteTexture || !g_Config.backend_info.bSupportsPaletteConversion)
					return ReturnEntry(stage, entry);

				// Note that we found an unconverted EFB copy, then continue.  We'll
				// perform the conversion later.  Currently, we only convert EFB copies to
				// palette textures; we could do other conversions if it proved to be
				// beneficial.
				unconverted_copy = iter;
			}
			else
			{
				// Aggressively prune EFB copies: if it isn't useful here, it will probably
				// never be useful again.  It's theoretically possible for a game to do
				// something weird where the copy could become useful in the future, but in
				// practice it doesn't happen.
				iter = FreeTexture(iter);
				continue;
			}
		}
		else
		{
			// For normal textures, all texture parameters need to match
			if (entry->hash == full_hash && entry->format == full_format && entry->native_levels >= tex_levels &&
				entry->native_width == nativeW && entry->native_height == nativeH)
			{
				entry = DoPartialTextureUpdates(iter);

				return ReturnEntry(stage, entry);
			}
		}

		// Find the texture which hasn't been used for the longest time. Count paletted
		// textures as the same texture here, when the texture itself is the same. This
		// improves the performance a lot in some games that use paletted textures.
		// Example: Sonic the Fighters (inside Sonic Gems Collection)
		// Skip EFB copies here, so they can be used for partial texture updates
		if (entry->frameCount != FRAMECOUNT_INVALID && entry->frameCount < temp_frameCount &&
			!entry->IsEfbCopy() && !(isPaletteTexture && entry->base_hash == base_hash))
		{
			temp_frameCount = entry->frameCount;
			oldest_entry = iter;
		}
		++iter;
	}

	if (unconverted_copy != textures_by_address.end())
	{
		// Perform palette decoding.
		TCacheEntryBase *entry = unconverted_copy->second;

		TCacheEntryConfig config;
		config.rendertarget = true;
		config.width = entry->config.width;
		config.height = entry->config.height;
		config.layers = FramebufferManagerBase::GetEFBLayers();
		TCacheEntryBase *decoded_entry = AllocateTexture(config);

		decoded_entry->SetGeneralParameters(address, texture_size, full_format);
		decoded_entry->SetDimensions(entry->native_width, entry->native_height, 1);
		decoded_entry->SetHashes(base_hash, full_hash);
		decoded_entry->frameCount = FRAMECOUNT_INVALID;
		decoded_entry->is_efb_copy = false;

		g_texture_cache->ConvertTexture(decoded_entry, entry, &texMem[tlutaddr], (TlutFormat)tlutfmt);
		textures_by_address.emplace((u64)address, decoded_entry);
		return ReturnEntry(stage, decoded_entry);
	}

	// Search the texture cache for normal textures by hash
	//
	// If the texture was fully hashed, the address does not need to match. Identical duplicate textures cause unnecessary slowdowns
	// Example: Tales of Symphonia (GC) uses over 500 small textures in menus, but only around 70 different ones
	if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 ||
		std::max(texture_size, palette_size) <= (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8)
	{
		iter_range = textures_by_hash.equal_range(full_hash);
		iter = iter_range.first;
		while (iter != iter_range.second)
		{
			TCacheEntryBase* entry = iter->second;
			// All parameters, except the address, need to match here
			if (entry->format == full_format && entry->native_levels >= tex_levels &&
				entry->native_width == nativeW && entry->native_height == nativeH)
			{
				entry = DoPartialTextureUpdates(iter);

				return ReturnEntry(stage, entry);
			}
			++iter;
		}
	}

	// If at least one entry was not used for the same frame, overwrite the oldest one
	if (temp_frameCount != 0x7fffffff)
	{
		// pool this texture and make a new one later
		FreeTexture(oldest_entry);
	}

	std::shared_ptr<HiresTexture> hires_tex;
	if (g_ActiveConfig.bHiresTextures)
	{
		hires_tex = HiresTexture::Search(
			src_data, texture_size,
			&texMem[tlutaddr], palette_size,
			width, height,
			texformat, use_mipmaps
		);

		if (hires_tex)
		{
			auto& l = hires_tex->m_levels[0];
			if (l.width != width || l.height != height)
			{
				width = l.width;
				height = l.height;
			}
			expandedWidth = l.width;
			expandedHeight = l.height;
			CheckTempSize(l.data_size);
			memcpy(temp, l.data, l.data_size);
		}
	}

	if (!hires_tex)
	{
		if (!(texformat == GX_TF_RGBA8 && from_tmem))
		{
			const u8* tlut = &texMem[tlutaddr];
			TexDecoder_Decode(temp, src_data, expandedWidth, expandedHeight, texformat, tlut, (TlutFormat)tlutfmt);
		}
		else
		{
			u8* src_data_gb = &texMem[bpmem.tex[stage / 4].texImage2[stage % 4].tmem_odd * TMEM_LINE_SIZE];
			TexDecoder_DecodeRGBA8FromTmem(temp, src_data, src_data_gb, expandedWidth, expandedHeight);
		}
	}

	// how many levels the allocated texture shall have
	const u32 texLevels = hires_tex ? (u32)hires_tex->m_levels.size() : tex_levels;

	// create the entry/texture
	TCacheEntryConfig config;
	config.width = width;
	config.height = height;
	config.levels = texLevels;

	TCacheEntryBase* entry = AllocateTexture(config);
	GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);

	iter = textures_by_address.emplace((u64)address, entry);
	if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 ||
		std::max(texture_size, palette_size) <= (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8)
	{
		entry->textures_by_hash_iter = textures_by_hash.emplace(full_hash, entry);
	}

	entry->SetGeneralParameters(address, texture_size, full_format);
	entry->SetDimensions(nativeW, nativeH, tex_levels);
	entry->SetHashes(base_hash, full_hash);
	entry->is_efb_copy = false;
	entry->is_custom_tex = hires_tex != nullptr;

	// load texture
	entry->Load(width, height, expandedWidth, 0);

	std::string basename = "";
	if (g_ActiveConfig.bDumpTextures && !hires_tex)
	{
		basename = HiresTexture::GenBaseName(
			src_data, texture_size,
			&texMem[tlutaddr], palette_size,
			width, height,
			texformat, use_mipmaps,
			true
		);
		DumpTexture(entry, basename, 0);
	}

	if (hires_tex)
	{
		for (u32 level = 1; level != texLevels; ++level)
		{
			auto& l = hires_tex->m_levels[level];
			CheckTempSize(l.data_size);
			memcpy(temp, l.data, l.data_size);
			entry->Load(l.width, l.height, l.width, level);
		}
	}
	else
	{
		// load mips - TODO: Loading mipmaps from tmem is untested!
		src_data += texture_size;

		const u8* ptr_even = nullptr;
		const u8* ptr_odd = nullptr;
		if (from_tmem)
		{
			ptr_even = &texMem[bpmem.tex[stage / 4].texImage1[stage % 4].tmem_even * TMEM_LINE_SIZE + texture_size];
			ptr_odd = &texMem[bpmem.tex[stage / 4].texImage2[stage % 4].tmem_odd * TMEM_LINE_SIZE];
		}

		for (u32 level = 1; level != texLevels; ++level)
		{
			const u32 mip_width = CalculateLevelSize(width, level);
			const u32 mip_height = CalculateLevelSize(height, level);
			const u32 expanded_mip_width = ROUND_UP(mip_width, bsw);
			const u32 expanded_mip_height = ROUND_UP(mip_height, bsh);

			const u8*& mip_src_data = from_tmem
				? ((level % 2) ? ptr_odd : ptr_even)
				: src_data;
			const u8* tlut = &texMem[tlutaddr];
			TexDecoder_Decode(temp, mip_src_data, expanded_mip_width, expanded_mip_height, texformat, tlut, (TlutFormat)tlutfmt);
			mip_src_data += TexDecoder_GetTextureSizeInBytes(expanded_mip_width, expanded_mip_height, texformat);

			entry->Load(mip_width, mip_height, expanded_mip_width, level);

			if (g_ActiveConfig.bDumpTextures)
				DumpTexture(entry, basename, level);
		}
	}

	INCSTAT(stats.numTexturesUploaded);
	SETSTAT(stats.numTexturesAlive, textures_by_address.size());

	entry = DoPartialTextureUpdates(iter);

	return ReturnEntry(stage, entry);
}
예제 #18
0
void TextureCacheBase::ScaleTextureCacheEntryTo(TextureCacheBase::TCacheEntryBase** entry, u32 new_width, u32 new_height)
{
	if ((*entry)->config.width == new_width && (*entry)->config.height == new_height)
	{
		return;
	}

	u32 max = g_renderer->GetMaxTextureSize();
	if (max < new_width || max < new_height)
	{
		ERROR_LOG(VIDEO, "Texture too big, width = %d, height = %d", new_width, new_height);
		return;
	}

	TextureCacheBase::TCacheEntryConfig newconfig;
	newconfig.width = new_width;
	newconfig.height = new_height;
	newconfig.layers = (*entry)->config.layers;
	newconfig.rendertarget = true;

	TCacheEntryBase* newentry = AllocateTexture(newconfig);
	if (newentry)
	{
		newentry->SetGeneralParameters((*entry)->addr, (*entry)->size_in_bytes, (*entry)->format);
		newentry->SetDimensions((*entry)->native_width, (*entry)->native_height, 1);
		newentry->SetHashes((*entry)->base_hash, (*entry)->hash);
		newentry->frameCount = frameCount;
		newentry->is_efb_copy = (*entry)->is_efb_copy;
		MathUtil::Rectangle<int> srcrect, dstrect;
		srcrect.left = 0;
		srcrect.top = 0;
		srcrect.right = (*entry)->config.width;
		srcrect.bottom = (*entry)->config.height;
		dstrect.left = 0;
		dstrect.top = 0;
		dstrect.right = new_width;
		dstrect.bottom = new_height;
		newentry->CopyRectangleFromTexture(*entry, srcrect, dstrect);

		// Keep track of the pointer for textures_by_hash
		if ((*entry)->textures_by_hash_iter != textures_by_hash.end())
		{
			newentry->textures_by_hash_iter = textures_by_hash.emplace((*entry)->hash, newentry);
		}

		// Remove the old texture
		std::pair<TexCache::iterator, TexCache::iterator>iter_range = textures_by_address.equal_range((*entry)->addr);
		TexCache::iterator iter = iter_range.first;
		while (iter != iter_range.second)
		{
			if (iter->second == *entry)
			{
				FreeTexture(iter);
				iter = iter_range.second;
			}
			else
			{
				iter++;
			}
		}

		*entry = newentry;
		textures_by_address.emplace((*entry)->addr, *entry);
	}
	else
	{
		ERROR_LOG(VIDEO, "Scaling failed");
	}
}
예제 #19
0
		OpenGL_DebugFont::~OpenGL_DebugFont()
		{
			FreeTexture( m_pFontTexture );
			delete m_pFontTexture;
		}
예제 #20
0
void CTextureMap::Flush()
{
    if (!m_referenceCount)
        FreeTexture();
}
예제 #21
0
TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(TexCache::iterator iter_t)
{
	TCacheEntryBase* entry_to_update = iter_t->second;
	const bool isPaletteTexture = (entry_to_update->format == GX_TF_C4
		|| entry_to_update->format == GX_TF_C8
		|| entry_to_update->format == GX_TF_C14X2
		|| entry_to_update->format >= 0x10000);

	// Efb copies and paletted textures are excluded from these updates, until there's an example where a game would
	// benefit from this. Both would require more work to be done.
	if (entry_to_update->IsEfbCopy()
		|| isPaletteTexture)
		return entry_to_update;

	u32 block_width = TexDecoder_GetBlockWidthInTexels(entry_to_update->format & 0xf);
	u32 block_height = TexDecoder_GetBlockHeightInTexels(entry_to_update->format & 0xf);
	u32 block_size = block_width * block_height * TexDecoder_GetTexelSizeInNibbles(entry_to_update->format & 0xf) / 2;

	u32 numBlocksX = (entry_to_update->native_width + block_width - 1) / block_width;

	TexCache::iterator iter = textures_by_address.lower_bound(entry_to_update->addr);
	TexCache::iterator iterend = textures_by_address.upper_bound(entry_to_update->addr + entry_to_update->size_in_bytes);
	while (iter != iterend)
	{
		TCacheEntryBase* entry = iter->second;
		if (entry != entry_to_update
			&& entry->IsEfbCopy()
			&& entry->OverlapsMemoryRange(entry_to_update->addr, entry_to_update->size_in_bytes)
			&& entry->frameCount == FRAMECOUNT_INVALID
			&& entry->memory_stride == numBlocksX * block_size)
		{
			if (entry->hash == entry->CalculateHash())
			{
				u32 src_x, src_y, dst_x, dst_y;

				// Note for understanding the math:
				// Normal textures can't be strided, so the 2 missing cases with src_x > 0 don't exist
				if (entry->addr >= entry_to_update->addr)
				{
					u32 block_offset = (entry->addr - entry_to_update->addr) / block_size;
					u32 block_x = block_offset % numBlocksX;
					u32 block_y = block_offset / numBlocksX;
					src_x = 0;
					src_y = 0;
					dst_x = block_x * block_width;
					dst_y = block_y * block_height;
				}
				else
				{
					u32 block_offset = (entry_to_update->addr - entry->addr) / block_size;
					u32 block_x = (~block_offset + 1) % numBlocksX;
					u32 block_y = (block_offset + block_x) / numBlocksX;
					src_x = 0;
					src_y = block_y * block_height;
					dst_x = block_x * block_width;
					dst_y = 0;
				}

				u32 copy_width = std::min(entry->native_width - src_x, entry_to_update->native_width - dst_x);
				u32 copy_height = std::min(entry->native_height - src_y, entry_to_update->native_height - dst_y);

				// If one of the textures is scaled, scale both with the current efb scaling factor
				if (entry_to_update->native_width != entry_to_update->config.width
					|| entry_to_update->native_height != entry_to_update->config.height
					|| entry->native_width != entry->config.width || entry->native_height != entry->config.height)
				{
					ScaleTextureCacheEntryTo(&entry_to_update, Renderer::EFBToScaledX(entry_to_update->native_width), Renderer::EFBToScaledY(entry_to_update->native_height));
					ScaleTextureCacheEntryTo(&entry, Renderer::EFBToScaledX(entry->native_width), Renderer::EFBToScaledY(entry->native_height));

					src_x = Renderer::EFBToScaledX(src_x);
					src_y = Renderer::EFBToScaledY(src_y);
					dst_x = Renderer::EFBToScaledX(dst_x);
					dst_y = Renderer::EFBToScaledY(dst_y);
					copy_width = Renderer::EFBToScaledX(copy_width);
					copy_height = Renderer::EFBToScaledY(copy_height);
				}

				MathUtil::Rectangle<int> srcrect, dstrect;
				srcrect.left = src_x;
				srcrect.top = src_y;
				srcrect.right = (src_x + copy_width);
				srcrect.bottom = (src_y + copy_height);
				dstrect.left = dst_x;
				dstrect.top = dst_y;
				dstrect.right = (dst_x + copy_width);
				dstrect.bottom = (dst_y + copy_height);
				entry_to_update->CopyRectangleFromTexture(entry, srcrect, dstrect);
				// Mark the texture update as used, so it isn't applied more than once
				entry->frameCount = frameCount;
			}
			else
			{
				// If the hash does not match, this EFB copy will not be used for anything, so remove it
				iter = FreeTexture(iter);
				continue;
			}
		}
		++iter;
	}
	return entry_to_update;
}
예제 #22
0
CCommonWnd::~CCommonWnd()
{
	if(m_pBackTexture)
		FreeTexture(m_pBackTexture);
}
예제 #23
0
CTextureMap::~CTextureMap()
{
    FreeTexture();
}
예제 #24
0
void CTex::FreeTexture (std::string name)
{
    FreeTexture (GetTexID (name));
}
예제 #25
0
/**
* Destructor
*/
Texture::~Texture ( )
{
	FreeTexture();
}
예제 #26
0
void FreeTexture(const char* texture_name)
{
	// just find font by name and free it, using FS_FreeFont(font_t*)

	FreeTexture(TextureByName(texture_name));
}
예제 #27
0
TextureCache::TCacheEntryBase* TextureCache::DoPartialTextureUpdates(TexCache::iterator iter_t)
{
	TCacheEntryBase* entry_to_update = iter_t->second;
	const bool isPaletteTexture = (entry_to_update->format == GX_TF_C4
		|| entry_to_update->format == GX_TF_C8
		|| entry_to_update->format == GX_TF_C14X2
		|| entry_to_update->format >= 0x10000);

	// Efb copies and paletted textures are excluded from these updates, until there's an example where a game would
	// benefit from this. Both would require more work to be done.
	// TODO: Implement upscaling support for normal textures, and then remove the efb to ram and the scaled efb restrictions
	if (entry_to_update->IsEfbCopy()
		|| isPaletteTexture)
		return entry_to_update;

	u32 block_width = TexDecoder_GetBlockWidthInTexels(entry_to_update->format);
	u32 block_height = TexDecoder_GetBlockHeightInTexels(entry_to_update->format);
	u32 block_size = block_width * block_height * TexDecoder_GetTexelSizeInNibbles(entry_to_update->format) / 2;

	u32 numBlocksX = (entry_to_update->native_width + block_width - 1) / block_width;

	TexCache::iterator iter = textures_by_address.lower_bound(entry_to_update->addr);
	TexCache::iterator iterend = textures_by_address.upper_bound(entry_to_update->addr + entry_to_update->size_in_bytes);
	bool entry_need_scaling = true;
	while (iter != iterend)
	{
		TCacheEntryBase* entry = iter->second;
		if (entry != entry_to_update
			&& entry->IsEfbCopy()
			&& entry_to_update->addr <= entry->addr
			&& entry->addr + entry->size_in_bytes <= entry_to_update->addr + entry_to_update->size_in_bytes
			&& entry->frameCount == FRAMECOUNT_INVALID
			&& entry->memory_stride == numBlocksX * block_size)
		{
			u32 block_offset = (entry->addr - entry_to_update->addr) / block_size;
			u32 block_x = block_offset % numBlocksX;
			u32 block_y = block_offset / numBlocksX;

			u32 x = block_x * block_width;
			u32 y = block_y * block_height;
			MathUtil::Rectangle<int> srcrect, dstrect;
			srcrect.left = 0;
			srcrect.top = 0;
			dstrect.left = 0;
			dstrect.top = 0;
			if (entry_need_scaling)
			{
				entry_need_scaling = false;
				u32 w = entry_to_update->native_width * entry->config.width / entry->native_width;
				u32 h = entry_to_update->native_height * entry->config.height / entry->native_height;
				u32 max = g_renderer->GetMaxTextureSize();
				if (max < w || max < h)
				{
					iter++;
					continue;
				}
				if (entry_to_update->config.width != w || entry_to_update->config.height != h)
				{
					TextureCache::TCacheEntryConfig newconfig;
					newconfig.width = w;
					newconfig.height = h;
					newconfig.rendertarget = true;
					TCacheEntryBase* newentry = AllocateTexture(newconfig);
					newentry->SetGeneralParameters(entry_to_update->addr, entry_to_update->size_in_bytes, entry_to_update->format);
					newentry->SetDimensions(entry_to_update->native_width, entry_to_update->native_height, 1);
					newentry->SetHashes(entry_to_update->base_hash, entry_to_update->hash);
					newentry->frameCount = frameCount;
					newentry->is_efb_copy = false;
					srcrect.right = entry_to_update->config.width;
					srcrect.bottom = entry_to_update->config.height;
					dstrect.right = w;
					dstrect.bottom = h;
					newentry->CopyRectangleFromTexture(entry_to_update, srcrect, dstrect);
					entry_to_update = newentry;
					u64 key = iter_t->first;
					iter_t = FreeTexture(iter_t);
					textures_by_address.emplace(key, entry_to_update);
				}
			}
			srcrect.right = entry->config.width;
			srcrect.bottom = entry->config.height;
			dstrect.left = x * entry_to_update->config.width / entry_to_update->native_width;
			dstrect.top = y * entry_to_update->config.height / entry_to_update->native_height;
			dstrect.right = (x + entry->native_width) * entry_to_update->config.width / entry_to_update->native_width;
			dstrect.bottom = (y + entry->native_height) * entry_to_update->config.height / entry_to_update->native_height;
			entry_to_update->CopyRectangleFromTexture(entry, srcrect, dstrect);
			// Mark the texture update as used, so it isn't applied more than once
			entry->frameCount = frameCount;
		}
		++iter;
	}
	return entry_to_update;
}
예제 #28
0
// WinMain
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow)
{
	MSG msg = {0};
	HWND hwnd = NULL;
	WNDCLASSEX wndclassex = {0};

	// Fill the fields we care about
	wndclassex.cbSize = sizeof(WNDCLASSEX);
	wndclassex.style = CS_HREDRAW | CS_VREDRAW;
	wndclassex.lpfnWndProc = WinProc;					
	wndclassex.hInstance = hinstance;	
	wndclassex.lpszClassName = class_name;
	wndclassex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wndclassex.hCursor = (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(IDC_ARROW),
											IMAGE_CURSOR, 0, 0, LR_SHARED);

	RegisterClassEx(&wndclassex); // Register the class

	RECT rect = { 0, 0, WIN_WID, WIN_HGT }; // Desired window client rect
	
	DWORD winStyleEx = WS_EX_APPWINDOW;
	DWORD winStyle = WS_CAPTION | WS_SYSMENU; // Window style

	// Adjust window rect so it gives us our desired client rect when we 
	// create the window
	AdjustWindowRectEx(&rect, winStyle, false, winStyleEx);

	// Create our window -- Notice how we set use different "variables" when creating
	// the window based upon if we were able to switch to full screen or not
	hwnd = CreateWindowEx(winStyleEx,
						  class_name,
						  "www.GameTutorials.com -- Texture Mapping",
						  winStyle,
						  CW_USEDEFAULT,
						  CW_USEDEFAULT,
						  rect.right - rect.left, // Window width
						  rect.bottom - rect.top, // Window height
						  NULL,
						  NULL,
						  hinstance,
						  NULL);

		// Error Check
		if(!hwnd)
			goto CLEAN_UP; // Here we are going to use goto in a "good" way
						   // We have a few things we want to initialize so if
						   // any of them fail, we just go to the "clean up code"
	
	// Get the client RECT
	GetClientRect(hwnd, &rect);
	
	// If the client width or height isn't what we requested, there's been
	// an error somewhere and we're going to bail ship
	if(rect.right != WIN_WID || rect.bottom != WIN_HGT)
		goto CLEAN_UP;
		
	HDC hdc = GetDC(hwnd); // Get the window's hdc

	// Initialize OpenGL
	if(gGLObj.init(hdc, 32, 32) == false)
		goto CLEAN_UP;

	// Load the texture
	if(LoadTexture() == false)
		goto CLEAN_UP;

	// Set up the view port
	gGLObj.setViewPort(WIN_WID,WIN_HGT,45.0);

	// Show and update window
    ShowWindow(hwnd, ishow);
    UpdateWindow(hwnd);

	while(1)
	{
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			if(msg.message == WM_QUIT)
				break;
				
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			gGLObj.begin(); // Begin to draw

				// Bind the texture
				glBindTexture(GL_TEXTURE_2D, gTextureID);

				// Draw a quad (ie a square)
				glBegin(GL_QUADS);

					// glTexCoord2f() takes a U and V (U,V) into our texture.  The U and V are 
					// in the range from 0 to 1.  And work like this:

					/*	  (0,1)  (1,1) 
						    _______
						   |	   |
						   |	   |
						   |	   |			Just like Cartesian coordinates :)
						    -------
						  (0,0)  (1,0)

					*/

					// Display the top left vertex
					glTexCoord2f(0.0f, 1.0f);
					glVertex3f(-1, 1, 0);

					// Display the bottom left vertex
					glTexCoord2f(0.0f, 0.0f);
					glVertex3f(-1, -1, 0);

					// Display the bottom right vertex
					glTexCoord2f(1.0f, 0.0f);
					glVertex3f(1, -1, 0);

					// Display the top right vertex
					glTexCoord2f(1.0f, 1.0f);
					glVertex3f(1, 1, 0);

				glEnd(); // Stop drawing QUADS

			gGLObj.end(); // End drawing in 3D and blit to the screen

		}
		
	} // end of while(1)

CLEAN_UP:

	if(hdc)
		ReleaseDC(hwnd, hdc); // Be sure to free up the window's HDC

	FreeTexture(); // Free the texture
	UnregisterClass(class_name,hinstance); // Free up the WNDCLASSEX
		return msg.wParam;
}
예제 #29
0
void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, u32 dstStride, PEControl::PixelFormat srcFormat,
	const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf)
{
	// Emulation methods:
	//
	// - EFB to RAM:
	//      Encodes the requested EFB data at its native resolution to the emulated RAM using shaders.
	//      Load() decodes the data from there again (using TextureDecoder) if the EFB copy is being used as a texture again.
	//      Advantage: CPU can read data from the EFB copy and we don't lose any important updates to the texture
	//      Disadvantage: Encoding+decoding steps often are redundant because only some games read or modify EFB copies before using them as textures.
	//
	// - EFB to texture:
	//      Copies the requested EFB data to a texture object in VRAM, performing any color conversion using shaders.
	//      Advantage: Works for many games, since in most cases EFB copies aren't read or modified at all before being used as a texture again.
	//                 Since we don't do any further encoding or decoding here, this method is much faster.
	//                 It also allows enhancing the visual quality by doing scaled EFB copies.
	//
	// - Hybrid EFB copies:
	//      1a) Whenever this function gets called, encode the requested EFB data to RAM (like EFB to RAM)
	//      1b) Set type to TCET_EC_DYNAMIC for all texture cache entries in the destination address range.
	//          If EFB copy caching is enabled, further checks will (try to) prevent redundant EFB copies.
	//      2) Check if a texture cache entry for the specified dstAddr already exists (i.e. if an EFB copy was triggered to that address before):
	//      2a) Entry doesn't exist:
	//          - Also copy the requested EFB data to a texture object in VRAM (like EFB to texture)
	//          - Create a texture cache entry for the target (type = TCET_EC_VRAM)
	//          - Store a hash of the encoded RAM data in the texcache entry.
	//      2b) Entry exists AND type is TCET_EC_VRAM:
	//          - Like case 2a, but reuse the old texcache entry instead of creating a new one.
	//      2c) Entry exists AND type is TCET_EC_DYNAMIC:
	//          - Only encode the texture to RAM (like EFB to RAM) and store a hash of the encoded data in the existing texcache entry.
	//          - Do NOT copy the requested EFB data to a VRAM object. Reason: the texture is dynamic, i.e. the CPU is modifying it. Storing a VRAM copy is useless, because we'd always end up deleting it and reloading the data from RAM anyway.
	//      3) If the EFB copy gets used as a texture, compare the source RAM hash with the hash you stored when encoding the EFB data to RAM.
	//      3a) If the two hashes match AND type is TCET_EC_VRAM, reuse the VRAM copy you created
	//      3b) If the two hashes differ AND type is TCET_EC_VRAM, screw your existing VRAM copy. Set type to TCET_EC_DYNAMIC.
	//          Redecode the source RAM data to a VRAM object. The entry basically behaves like a normal texture now.
	//      3c) If type is TCET_EC_DYNAMIC, treat the EFB copy like a normal texture.
	//      Advantage: Non-dynamic EFB copies can be visually enhanced like with EFB to texture.
	//                 Compatibility is as good as EFB to RAM.
	//      Disadvantage: Slower than EFB to texture and often even slower than EFB to RAM.
	//                    EFB copy cache depends on accurate texture hashing being enabled. However, with accurate hashing you end up being as slow as without a copy cache anyway.
	//
	// Disadvantage of all methods: Calling this function requires the GPU to perform a pipeline flush which stalls any further CPU processing.
	//
	// For historical reasons, Dolphin doesn't actually implement "pure" EFB to RAM emulation, but only EFB to texture and hybrid EFB copies.

	float colmat[28] = { 0 };
	float *const fConstAdd = colmat + 16;
	float *const ColorMask = colmat + 20;
	ColorMask[0] = ColorMask[1] = ColorMask[2] = ColorMask[3] = 255.0f;
	ColorMask[4] = ColorMask[5] = ColorMask[6] = ColorMask[7] = 1.0f / 255.0f;
	unsigned int cbufid = -1;
	bool efbHasAlpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24;

	if (srcFormat == PEControl::Z24)
	{
		switch (dstFormat)
		{
		case 0: // Z4
			colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1.0f;
			cbufid = 0;
			dstFormat |= _GX_TF_CTF;
			break;
		case 8: // Z8H
			dstFormat |= _GX_TF_CTF;
		case 1: // Z8
			colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1.0f;
			cbufid = 1;
			break;

		case 3: // Z16
			colmat[1] = colmat[5] = colmat[9] = colmat[12] = 1.0f;
			cbufid = 2;
			break;

		case 11: // Z16 (reverse order)
			colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f;
			cbufid = 3;
			dstFormat |= _GX_TF_CTF;
			break;

		case 6: // Z24X8
			colmat[0] = colmat[5] = colmat[10] = 1.0f;
			cbufid = 4;
			break;

		case 9: // Z8M
			colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f;
			cbufid = 5;
			dstFormat |= _GX_TF_CTF;
			break;

		case 10: // Z8L
			colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f;
			cbufid = 6;
			dstFormat |= _GX_TF_CTF;
			break;

		case 12: // Z16L - copy lower 16 depth bits
			// expected to be used as an IA8 texture (upper 8 bits stored as intensity, lower 8 bits stored as alpha)
			// Used e.g. in Zelda: Skyward Sword
			colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f;
			cbufid = 7;
			dstFormat |= _GX_TF_CTF;
			break;

		default:
			ERROR_LOG(VIDEO, "Unknown copy zbuf format: 0x%x", dstFormat);
			colmat[2] = colmat[5] = colmat[8] = 1.0f;
			cbufid = 8;
			break;
		}

		dstFormat |= _GX_TF_ZTF;
	}
	else if (isIntensity)
	{
		fConstAdd[0] = fConstAdd[1] = fConstAdd[2] = 16.0f / 255.0f;
		switch (dstFormat)
		{
		case 0: // I4
		case 1: // I8
		case 2: // IA4
		case 3: // IA8
		case 8: // I8
			// TODO - verify these coefficients
			colmat[0] = 0.257f; colmat[1] = 0.504f; colmat[2] = 0.098f;
			colmat[4] = 0.257f; colmat[5] = 0.504f; colmat[6] = 0.098f;
			colmat[8] = 0.257f; colmat[9] = 0.504f; colmat[10] = 0.098f;

			if (dstFormat < 2 || dstFormat == 8)
			{
				colmat[12] = 0.257f; colmat[13] = 0.504f; colmat[14] = 0.098f;
				fConstAdd[3] = 16.0f / 255.0f;
				if (dstFormat == 0)
				{
					ColorMask[0] = ColorMask[1] = ColorMask[2] = 15.0f;
					ColorMask[4] = ColorMask[5] = ColorMask[6] = 1.0f / 15.0f;
					cbufid = 9;
				}
				else
				{
					cbufid = 10;
				}
			}
			else// alpha
			{
				colmat[15] = 1;
				if (dstFormat == 2)
				{
					ColorMask[0] = ColorMask[1] = ColorMask[2] = ColorMask[3] = 15.0f;
					ColorMask[4] = ColorMask[5] = ColorMask[6] = ColorMask[7] = 1.0f / 15.0f;
					cbufid = 11;
				}
				else
				{
					cbufid = 12;
				}

			}
			break;

		default:
			ERROR_LOG(VIDEO, "Unknown copy intensity format: 0x%x", dstFormat);
			colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f;
			cbufid = 13;
			break;
		}
	}
	else
	{
		switch (dstFormat)
		{
		case 0: // R4
			colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1;
			ColorMask[0] = 15.0f;
			ColorMask[4] = 1.0f / 15.0f;
			cbufid = 14;
			dstFormat |= _GX_TF_CTF;
			break;
		case 1: // R8
		case 8: // R8
			colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1;
			cbufid = 15;
			dstFormat |= _GX_TF_CTF;
			break;

		case 2: // RA4
			colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1.0f;
			ColorMask[0] = ColorMask[3] = 15.0f;
			ColorMask[4] = ColorMask[7] = 1.0f / 15.0f;

			cbufid = 16;
			if (!efbHasAlpha)
			{
				ColorMask[3] = 0.0f;
				fConstAdd[3] = 1.0f;
				cbufid = 17;
			}
			dstFormat |= _GX_TF_CTF;
			break;
		case 3: // RA8
			colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1.0f;

			cbufid = 18;
			if (!efbHasAlpha)
			{
				ColorMask[3] = 0.0f;
				fConstAdd[3] = 1.0f;
				cbufid = 19;
			}
			dstFormat |= _GX_TF_CTF;
			break;

		case 7: // A8
			colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1.0f;

			cbufid = 20;
			if (!efbHasAlpha)
			{
				ColorMask[3] = 0.0f;
				fConstAdd[0] = 1.0f;
				fConstAdd[1] = 1.0f;
				fConstAdd[2] = 1.0f;
				fConstAdd[3] = 1.0f;
				cbufid = 21;
			}
			dstFormat |= _GX_TF_CTF;
			break;

		case 9: // G8
			colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f;
			cbufid = 22;
			dstFormat |= _GX_TF_CTF;
			break;
		case 10: // B8
			colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f;
			cbufid = 23;
			dstFormat |= _GX_TF_CTF;
			break;

		case 11: // RG8
			colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f;
			cbufid = 24;
			dstFormat |= _GX_TF_CTF;
			break;

		case 12: // GB8
			colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f;
			cbufid = 25;
			dstFormat |= _GX_TF_CTF;
			break;

		case 4: // RGB565
			colmat[0] = colmat[5] = colmat[10] = 1.0f;
			ColorMask[0] = ColorMask[2] = 31.0f;
			ColorMask[4] = ColorMask[6] = 1.0f / 31.0f;
			ColorMask[1] = 63.0f;
			ColorMask[5] = 1.0f / 63.0f;
			fConstAdd[3] = 1.0f; // set alpha to 1
			cbufid = 26;
			break;

		case 5: // RGB5A3
			colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f;
			ColorMask[0] = ColorMask[1] = ColorMask[2] = 31.0f;
			ColorMask[4] = ColorMask[5] = ColorMask[6] = 1.0f / 31.0f;
			ColorMask[3] = 7.0f;
			ColorMask[7] = 1.0f / 7.0f;

			cbufid = 27;
			if (!efbHasAlpha)
			{
				ColorMask[3] = 0.0f;
				fConstAdd[3] = 1.0f;
				cbufid = 28;
			}
			break;
		case 6: // RGBA8
			colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f;

			cbufid = 29;
			if (!efbHasAlpha)
			{
				ColorMask[3] = 0.0f;
				fConstAdd[3] = 1.0f;
				cbufid = 30;
			}
			break;

		default:
			ERROR_LOG(VIDEO, "Unknown copy color format: 0x%x", dstFormat);
			colmat[0] = colmat[5] = colmat[10] = colmat[15] = 1.0f;
			cbufid = 31;
			break;
		}
	}

	u8* dst = Memory::GetPointer(dstAddr);
	if (dst == nullptr)
	{
		ERROR_LOG(VIDEO, "Trying to copy from EFB to invalid address 0x%8x", dstAddr);
		return;
	}

	const unsigned int tex_w = scaleByHalf ? srcRect.GetWidth() / 2 : srcRect.GetWidth();
	const unsigned int tex_h = scaleByHalf ? srcRect.GetHeight() / 2 : srcRect.GetHeight();

	unsigned int scaled_tex_w = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledX(tex_w) : tex_w;
	unsigned int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledY(tex_h) : tex_h;

	// remove all texture cache entries at dstAddr
	{
		std::pair<TexCache::iterator, TexCache::iterator> iter_range = textures_by_address.equal_range((u64)dstAddr);
		TexCache::iterator iter = iter_range.first;
		while (iter != iter_range.second)
		{
			iter = FreeTexture(iter);
		}
	}

	// create the texture
	TCacheEntryConfig config;
	config.rendertarget = true;
	config.width = scaled_tex_w;
	config.height = scaled_tex_h;
	config.layers = FramebufferManagerBase::GetEFBLayers();

	TCacheEntryBase* entry = AllocateTexture(config);

	entry->SetGeneralParameters(dstAddr, 0, dstFormat);
	entry->SetDimensions(tex_w, tex_h, 1);

	entry->frameCount = FRAMECOUNT_INVALID;
	entry->SetEfbCopy(dstStride);
	entry->is_custom_tex = false;

	entry->FromRenderTarget(dst, dstFormat, dstStride, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat);

	u64 hash = entry->CalculateHash();
	entry->SetHashes(hash, hash);

	// Invalidate all textures that overlap the range of our efb copy.
	// Unless our efb copy has a weird stride, then we want avoid invalidating textures which
	// we might be able to do a partial texture update on.
	if (entry->memory_stride == entry->CacheLinesPerRow() * 32)
	{
		TexCache::iterator iter = textures_by_address.begin();
		while (iter != textures_by_address.end())
		{
			if (iter->second->OverlapsMemoryRange(dstAddr, entry->size_in_bytes))
				iter = FreeTexture(iter);
			else
				++iter;
		}
	}

	if (g_ActiveConfig.bDumpEFBTarget)
	{
		static int count = 0;
		entry->Save(StringFromFormat("%sefb_frame_%i.png", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
			count++), 0);
	}

	if (g_bRecordFifoData)
	{
		// Mark the memory behind this efb copy as dynamicly generated for the Fifo log
		u32 address = dstAddr;
		for (u32 i = 0; i < entry->NumBlocksY(); i++)
		{
			FifoRecorder::GetInstance().UseMemory(address, entry->CacheLinesPerRow() * 32, MemoryUpdate::TEXTURE_MAP, true);
			address += entry->memory_stride;
		}
	}

	textures_by_address.emplace((u64)dstAddr, entry);
}
예제 #30
0
void display (void) {
    
    glClearColor (0.0,0.0,0.0,1.0); //clear the screen to black
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //clear the color buffer and the depth buffer
    glMatrixMode( GL_MODELVIEW );
    glColor4f(1.0f,0.0f,0.0f,1.0f);
    
    glEnable(GL_SCISSOR_TEST);
    glMatrixMode (GL_PROJECTION); //set the matrix to projection
    
    // Draw the primary view
    glViewport (0, 0, (GLsizei)screen_width, (GLsizei)screen_height); //set the viewport to the current window specifications
    glScissor(0, 0, (GLsizei)screen_width, (GLsizei)screen_height);
    glLoadIdentity ();
    
    if (lighting) {
        GLfloat AmbientLight[] = {0.1, 0.1, 0.2};
        glLightfv (GL_LIGHT0, GL_AMBIENT, AmbientLight);
        GLfloat DiffuseLight[] = {1, 1, 1};
        glLightfv (GL_LIGHT1, GL_DIFFUSE, DiffuseLight);
        GLfloat LightPosition[] = {xpos, ypos, zpos, 1};
        glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
    }
    gluPerspective (60, (GLfloat)screen_width / (GLfloat)screen_height, 1.0, 100.0);
    gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); //camera position, x,y,z, looking at x,y,z, Up Positions of the camera
    camera();
    glPushMatrix();
    if (lighting) {
        texture1 = LoadTexture( "texture.raw", 256, 256 );
        texture2 = LoadTexture( "/dev/urandom", 256, 256 );
        texture3 = LoadTexture( "water.raw", 500, 375 );
        texture4 = LoadTexture( "bubbles.raw", 200, 200 );
        glEnable( GL_TEXTURE_2D ); //enable 2D texturing
        glEnable(GL_TEXTURE_GEN_S); //enable texture coordinate generation
        glEnable(GL_TEXTURE_GEN_T);
        
        if (fog) {
            GLfloat fogColor[4]= {0.5f, 1.0f, 0.5f, 1};  // Fog Color
            glFogi(GL_FOG_MODE, GL_EXP);        // Fog Mode
            glFogfv(GL_FOG_COLOR, fogColor);    // Set Fog Color
            glFogf(GL_FOG_DENSITY, 1.0f);       // How Dense Will The Fog Be
            glHint(GL_FOG_HINT, GL_DONT_CARE);  // Fog Hint Value
            glFogf(GL_FOG_START, n*space);      // Fog Start Depth
            glFogf(GL_FOG_END,-n*space);          // Fog End Depth
        }
        
        if (nurb) {
            glPushMatrix();
            glRotatef(270,0.0,1.0,0.0);
            glTranslated(n*space/2,n*space/2,-n*space);
            GLfloat ctlpoints[4][4][3];
            GLUnurbsObj *theNurb;
            GLfloat knots[8] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0};
            int u, v;
            for (u = 0; u < 4; u++) {
               for (v = 0; v < 4; v++) {
                  ctlpoints[u][v][0] = 2.0*((GLfloat)u - 1.5);
                  ctlpoints[u][v][1] = 2.0*((GLfloat)v - 1.5);

                  if ( (u == 1 || u == 2) && (v == 1 || v == 2))
                     ctlpoints[u][v][2] = 3.0;
                  else
                     ctlpoints[u][v][2] = -3.0;
               }
            }

            theNurb = gluNewNurbsRenderer();
            gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0);
            gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);
            gluBeginSurface(theNurb);
            gluNurbsSurface(theNurb, 
                               8, knots, 8, knots,
                               4 * 3, 3, &ctlpoints[0][0][0], 
                               4, 4, GL_MAP2_VERTEX_3);
            gluEndSurface(theNurb);
            glPopMatrix();
        }
    }
    cube(); //call the cube drawing function
    glPopMatrix();
    if (lighting) {
        FreeTexture( texture1 );
        FreeTexture( texture2 );
        FreeTexture( texture3 );
        FreeTexture( texture4 );
    }
    glPushMatrix();
    glTranslated(space*((n/2)+1),space*(n/2),space*(n/2));
    glutWireCube(space*n);
    glPopMatrix();
    
    // Draw the secondary view
    glViewport (3*(screen_width/4), 3*(screen_height/4), screen_width/4, screen_width/4); //set the viewport to the current window specifications
    glScissor(3*(screen_width/4), 3*(screen_height/4), screen_width/4, screen_width/4);
    glLoadIdentity();
    glOrtho(-1, 13, -1, 13, -1, 13);
    glRotatef(90,0.0,1.0,0.0); 
    cube();
    glDisable(GL_SCISSOR_TEST);
    glutSwapBuffers(); //swap the buffers
}