// Should be scale free.
void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture)
{
	u8* srcAddr = Memory::GetPointer(xfbAddr);
	if (!srcAddr)
	{
		WARN_LOG(VIDEO, "Tried to decode from invalid memory address");
		return;
	}

	g_renderer->ResetAPIState(); // reset any game specific settings

	OpenGL_BindAttributelessVAO();

	// switch to texture converter frame buffer
	// attach destTexture as color destination
	FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[1]);
	FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_ARRAY, destTexture, 0);

	// activate source texture
	// set srcAddr as data for source texture
	glActiveTexture(GL_TEXTURE9);
	glBindTexture(GL_TEXTURE_2D, s_srcTexture);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, srcWidth / 2, srcHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, srcAddr);
	g_sampler_cache->BindNearestSampler(9);

	glViewport(0, 0, srcWidth, srcHeight);
	s_yuyvToRgbProgram.Bind();

	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	FramebufferManager::SetFramebuffer(0);

	g_renderer->RestoreAPIState();
}
void FramebufferManager::ReinterpretPixelData(unsigned int convtype)
{
  g_renderer->ResetAPIState();

  OpenGL_BindAttributelessVAO();

  GLuint src_texture = 0;

  // We aren't allowed to render and sample the same texture in one draw call,
  // so we have to create a new texture and overwrite it completely.
  // To not allocate one big texture every time, we've allocated two on
  // initialization and just swap them here:
  src_texture = m_efbColor;
  m_efbColor = m_efbColorSwap;
  m_efbColorSwap = src_texture;
  FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_textureType, m_efbColor, 0);

  glViewport(0, 0, m_targetWidth, m_targetHeight);
  glActiveTexture(GL_TEXTURE9);
  glBindTexture(m_textureType, src_texture);
  g_sampler_cache->BindNearestSampler(9);

  m_pixel_format_shaders[convtype ? 1 : 0].Bind();
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  glBindTexture(m_textureType, 0);

  g_renderer->RestoreAPIState();
}
static void EncodeToRamUsingShader(GLuint srcTexture,
						u8* destAddr, u32 dst_line_size, u32 dstHeight,
						u32 writeStride, bool linearFilter)
{
	// switch to texture converter frame buffer
	// attach render buffer as color destination
	FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[0]);

	OpenGL_BindAttributelessVAO();

	// set source texture
	glActiveTexture(GL_TEXTURE9);
	glBindTexture(GL_TEXTURE_2D_ARRAY, srcTexture);

	if (linearFilter)
		g_sampler_cache->BindLinearSampler(9);
	else
		g_sampler_cache->BindNearestSampler(9);

	glViewport(0, 0, (GLsizei)(dst_line_size / 4), (GLsizei)dstHeight);

	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	int dstSize = dst_line_size * dstHeight;

	if ((writeStride != dst_line_size) && (dstHeight > 1))
	{
		// writing to a texture of a different size
		// also copy more then one block line, so the different strides matters
		// copy into one pbo first, map this buffer, and then memcpy into GC memory
		// in this way, we only have one vram->ram transfer, but maybe a bigger
		// CPU overhead because of the pbo
		glBindBuffer(GL_PIXEL_PACK_BUFFER, s_PBO);
		glBufferData(GL_PIXEL_PACK_BUFFER, dstSize, nullptr, GL_STREAM_READ);
		glReadPixels(0, 0, (GLsizei)(dst_line_size / 4), (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);
		u8* pbo = (u8*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, dstSize, GL_MAP_READ_BIT);

		for (size_t i = 0; i < dstHeight; ++i)
		{
			memcpy(destAddr, pbo, dst_line_size);
			pbo += dst_line_size;
			destAddr += writeStride;
		}

		glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
		glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
	}
	else
	{
		glReadPixels(0, 0, (GLsizei)(dst_line_size / 4), (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr);
	}
}
void OpenGLPostProcessing::BlitFromTexture(TargetRectangle src, TargetRectangle dst,
                                           int src_texture, int src_width, int src_height, int layer)
{
	ApplyShader();

	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

	glViewport(dst.left, dst.bottom, dst.GetWidth(), dst.GetHeight());

	OpenGL_BindAttributelessVAO();

	m_shader.Bind();

	glUniform4f(m_uniform_resolution, (float)src_width, (float)src_height, 1.0f / (float)src_width, 1.0f / (float)src_height);
	glUniform4f(m_uniform_src_rect, src.left / (float) src_width, src.bottom / (float) src_height,
		    src.GetWidth() / (float) src_width, src.GetHeight() / (float) src_height);
	glUniform1ui(m_uniform_time, (GLuint)m_timer.GetTimeElapsed());
	glUniform1i(m_uniform_layer, layer);

	if (m_config.IsDirty())
	{
		for (auto& it : m_config.GetOptions())
		{
			if (it.second.m_dirty)
			{
				switch (it.second.m_type)
				{
				case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL:
					glUniform1i(m_uniform_bindings[it.first], it.second.m_bool_value);
				break;
				case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_INTEGER:
					switch (it.second.m_integer_values.size())
					{
					case 1:
						glUniform1i(m_uniform_bindings[it.first], it.second.m_integer_values[0]);
					break;
					case 2:
						glUniform2i(m_uniform_bindings[it.first],
								it.second.m_integer_values[0],
						            it.second.m_integer_values[1]);
					break;
					case 3:
						glUniform3i(m_uniform_bindings[it.first],
								it.second.m_integer_values[0],
								it.second.m_integer_values[1],
						            it.second.m_integer_values[2]);
					break;
					case 4:
						glUniform4i(m_uniform_bindings[it.first],
								it.second.m_integer_values[0],
								it.second.m_integer_values[1],
								it.second.m_integer_values[2],
						            it.second.m_integer_values[3]);
					break;
					}
				break;
				case PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_FLOAT:
					switch (it.second.m_float_values.size())
					{
					case 1:
						glUniform1f(m_uniform_bindings[it.first], it.second.m_float_values[0]);
					break;
					case 2:
						glUniform2f(m_uniform_bindings[it.first],
								it.second.m_float_values[0],
						            it.second.m_float_values[1]);
					break;
					case 3:
						glUniform3f(m_uniform_bindings[it.first],
								it.second.m_float_values[0],
								it.second.m_float_values[1],
						            it.second.m_float_values[2]);
					break;
					case 4:
						glUniform4f(m_uniform_bindings[it.first],
								it.second.m_float_values[0],
								it.second.m_float_values[1],
								it.second.m_float_values[2],
						            it.second.m_float_values[3]);
					break;
					}
				break;
				}
				it.second.m_dirty = false;
			}
		}
		m_config.SetDirty(false);
	}

	glActiveTexture(GL_TEXTURE9);
	glBindTexture(GL_TEXTURE_2D_ARRAY, src_texture);
	g_sampler_cache->BindLinearSampler(9);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
static void EncodeToRamUsingShader(GLuint srcTexture,
						u8* destAddr, int dstWidth, int dstHeight, int readStride,
						bool linearFilter)
{


	// switch to texture converter frame buffer
	// attach render buffer as color destination
	FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[0]);

	OpenGL_BindAttributelessVAO();

	// set source texture
	glActiveTexture(GL_TEXTURE0+9);
	glBindTexture(GL_TEXTURE_2D_ARRAY, srcTexture);

	if (linearFilter)
	{
		glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	}
	else
	{
		glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	}

	glViewport(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight);

	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	// .. and then read back the results.
	// TODO: make this less slow.

	int writeStride = bpmem.copyMipMapStrideChannels * 32;
	int dstSize = dstWidth*dstHeight*4;
	int readHeight = readStride / dstWidth / 4; // 4 bytes per pixel
	int readLoops = dstHeight / readHeight;

	if (writeStride != readStride && readLoops > 1)
	{
		// writing to a texture of a different size
		// also copy more then one block line, so the different strides matters
		// copy into one pbo first, map this buffer, and then memcpy into GC memory
		// in this way, we only have one vram->ram transfer, but maybe a bigger
		// CPU overhead because of the pbo
		glBindBuffer(GL_PIXEL_PACK_BUFFER, s_PBO);
		glBufferData(GL_PIXEL_PACK_BUFFER, dstSize, nullptr, GL_STREAM_READ);
		glReadPixels(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);
		u8* pbo = (u8*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, dstSize, GL_MAP_READ_BIT);

		for (int i = 0; i < readLoops; i++)
		{
			memcpy(destAddr, pbo, readStride);
			pbo += readStride;
			destAddr += writeStride;
		}

		glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
		glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
	}
	else
	{
		glReadPixels(0, 0, (GLsizei)dstWidth, (GLsizei)dstHeight, GL_BGRA, GL_UNSIGNED_BYTE, destAddr);
	}
}
Exemple #6
0
void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
	PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
	bool isIntensity, bool scaleByHalf, unsigned int cbufid,
	const float *colmat)
{
	g_renderer->ResetAPIState(); // reset any game specific settings

	// Make sure to resolve anything we need to read from.
	const GLuint read_texture = (srcFormat == PEControl::Z24) ?
		FramebufferManager::ResolveAndGetDepthTarget(srcRect) :
		FramebufferManager::ResolveAndGetRenderTarget(srcRect);

	if (type != TCET_EC_DYNAMIC || g_ActiveConfig.bCopyEFBToTexture)
	{
		FramebufferManager::SetFramebuffer(framebuffer);

		OpenGL_BindAttributelessVAO();

		glActiveTexture(GL_TEXTURE0+9);
		glBindTexture(GL_TEXTURE_2D_ARRAY, read_texture);

		glViewport(0, 0, virtual_width, virtual_height);

		GLuint uniform_location;
		if (srcFormat == PEControl::Z24)
		{
			s_DepthMatrixProgram.Bind();
			if (s_DepthCbufid != cbufid)
				glUniform4fv(s_DepthMatrixUniform, 5, colmat);
			s_DepthCbufid = cbufid;
			uniform_location = s_DepthCopyPositionUniform;
		}
		else
		{
			s_ColorMatrixProgram.Bind();
			if (s_ColorCbufid != cbufid)
				glUniform4fv(s_ColorMatrixUniform, 7, colmat);
			s_ColorCbufid = cbufid;
			uniform_location = s_ColorCopyPositionUniform;
		}

		TargetRectangle R = g_renderer->ConvertEFBRectangle(srcRect);
		glUniform4f(uniform_location, static_cast<float>(R.left), static_cast<float>(R.top),
			static_cast<float>(R.right), static_cast<float>(R.bottom));

		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	}

	if (false == g_ActiveConfig.bCopyEFBToTexture)
	{
		int encoded_size = TextureConverter::EncodeToRamFromTexture(
			addr,
			read_texture,
			srcFormat == PEControl::Z24,
			isIntensity,
			dstFormat,
			scaleByHalf,
			srcRect);

		u8* dst = Memory::GetPointer(addr);
		u64 const new_hash = GetHash64(dst,encoded_size,g_ActiveConfig.iSafeTextureCache_ColorSamples);

		// Mark texture entries in destination address range dynamic unless caching is enabled and the texture entry is up to date
		if (!g_ActiveConfig.bEFBCopyCacheEnable)
			TextureCache::MakeRangeDynamic(addr,encoded_size);
		else if (!TextureCache::Find(addr, new_hash))
			TextureCache::MakeRangeDynamic(addr,encoded_size);

		hash = new_hash;
	}

	FramebufferManager::SetFramebuffer(0);

	if (g_ActiveConfig.bDumpEFBTarget)
	{
		static int count = 0;
		SaveTexture(StringFromFormat("%sefb_frame_%i.png", File::GetUserPath(D_DUMPTEXTURES_IDX).c_str(),
			count++), GL_TEXTURE_2D_ARRAY, texture, virtual_width, virtual_height, 0);
	}

	g_renderer->RestoreAPIState();
}