void PSTextureEncoder::Encode(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half) { if (!m_ready) // Make sure we initialized OK return; HRESULT hr; // Resolve MSAA targets before copying. // FIXME: Instead of resolving EFB, it would be better to pick out a // single sample from each pixel. The game may break if it isn't // expecting the blurred edges around multisampled shapes. ID3D11ShaderResourceView* pEFB = is_depth_copy ? FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() : FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); // Reset API g_renderer->ResetAPIState(); // Set up all the state for EFB encoding { const u32 words_per_row = bytes_per_row / sizeof(u32); D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(words_per_row), FLOAT(num_blocks_y)); D3D::context->RSSetViewports(1, &vp); constexpr EFBRectangle fullSrcRect(0, 0, EFB_WIDTH, EFB_HEIGHT); TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(fullSrcRect); D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr); EFBEncodeParams params; params.SrcLeft = src_rect.left; params.SrcTop = src_rect.top; params.DestWidth = native_width; params.ScaleFactor = scale_by_half ? 2 : 1; D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, ¶ms, 0, 0); D3D::stateman->SetPixelConstants(m_encodeParams); // We also linear filtering for both box filtering and downsampling higher resolutions to 1x // TODO: This only produces perfect downsampling for 1.5x and 2x IR, other resolution will // need more complex down filtering to average all pixels and produce the correct result. // Also, box filtering won't be correct for anything other than 1x IR if (scale_by_half || g_ActiveConfig.iEFBScale != SCALE_1X) D3D::SetLinearCopySampler(); else D3D::SetPointCopySampler(); D3D::drawShadedTexQuad(pEFB, targetRect.AsRECT(), g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(), GetEncodingPixelShader(format), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout()); // Copy to staging buffer D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, words_per_row, num_blocks_y, 1); D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox); // Transfer staging buffer to GameCube/Wii RAM D3D11_MAPPED_SUBRESOURCE map = {0}; hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map); CHECK(SUCCEEDED(hr), "map staging buffer (0x%x)", hr); u8* src = (u8*)map.pData; u32 readStride = std::min(bytes_per_row, map.RowPitch); for (unsigned int y = 0; y < num_blocks_y; ++y) { memcpy(dst, src, readStride); dst += memory_stride; src += map.RowPitch; } D3D::context->Unmap(m_outStage, 0); } // Restore API g_renderer->RestoreAPIState(); D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); }
void PSTextureEncoder::Encode(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect, bool scale_by_half) { // Resolve MSAA targets before copying. // FIXME: Instead of resolving EFB, it would be better to pick out a // single sample from each pixel. The game may break if it isn't // expecting the blurred edges around multisampled shapes. ID3D11ShaderResourceView* pEFB = params.depth ? FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() : FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); // Reset API g_renderer->ResetAPIState(); // Set up all the state for EFB encoding { const u32 words_per_row = bytes_per_row / sizeof(u32); D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(words_per_row), FLOAT(num_blocks_y)); D3D::context->RSSetViewports(1, &vp); constexpr EFBRectangle fullSrcRect(0, 0, EFB_WIDTH, EFB_HEIGHT); TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(fullSrcRect); D3D::context->OMSetRenderTargets( 1, &static_cast<DXTexture*>(m_encoding_render_texture.get())->GetRawTexIdentifier()->GetRTV(), nullptr); EFBEncodeParams encode_params; encode_params.SrcLeft = src_rect.left; encode_params.SrcTop = src_rect.top; encode_params.DestWidth = native_width; encode_params.ScaleFactor = scale_by_half ? 2 : 1; encode_params.y_scale = params.y_scale; D3D::context->UpdateSubresource(m_encode_params, 0, nullptr, &encode_params, 0, 0); D3D::stateman->SetPixelConstants(m_encode_params); // We also linear filtering for both box filtering and downsampling higher resolutions to 1x // TODO: This only produces perfect downsampling for 2x IR, other resolutions will need more // complex down filtering to average all pixels and produce the correct result. // Also, box filtering won't be correct for anything other than 1x IR if (scale_by_half || g_renderer->GetEFBScale() != 1 || params.y_scale > 1.0f) D3D::SetLinearCopySampler(); else D3D::SetPointCopySampler(); D3D::drawShadedTexQuad(pEFB, targetRect.AsRECT(), g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(), GetEncodingPixelShader(params), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout()); // Copy to staging buffer MathUtil::Rectangle<int> copy_rect(0, 0, words_per_row, num_blocks_y); m_encoding_readback_texture->CopyFromTexture(m_encoding_render_texture.get(), copy_rect, 0, 0, copy_rect); m_encoding_readback_texture->Flush(); if (m_encoding_readback_texture->Map()) { m_encoding_readback_texture->ReadTexels(copy_rect, dst, memory_stride); m_encoding_readback_texture->Unmap(); } } // Restore API FramebufferManager::BindEFBRenderTarget(); g_renderer->RestoreAPIState(); }