void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int src_pitch, unsigned int level, D3D11_USAGE usage) { if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING) { D3D11_MAPPED_SUBRESOURCE map; D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map); if (src_pitch == map.RowPitch) { memcpy(map.pData, buffer, map.RowPitch * height); } else { // Source row size is aligned to texture block size. This can result in a different // pitch to what the driver returns, so copy whichever is smaller. unsigned int copy_size = std::min(src_pitch, map.RowPitch); for (unsigned int y = 0; y < height; ++y) memcpy((u8*)map.pData + y * map.RowPitch, buffer + y * src_pitch, copy_size); } D3D::context->Unmap(pTexture, level); } else { D3D11_BOX dest_region = CD3D11_BOX(0, 0, 0, width, height, 1); D3D::context->UpdateSubresource(pTexture, level, &dest_region, buffer, src_pitch, src_pitch * height); } }
void Television::Submit(u32 xfbAddr, u32 width, u32 height) { m_curAddr = xfbAddr; m_curWidth = width; m_curHeight = height; // Load data from GameCube RAM to YUYV texture u8* yuyvSrc = Memory::GetPointer(xfbAddr); D3D11_BOX box = CD3D11_BOX(0, 0, 0, width, height, 1); D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2*width, 2*width*height); }
void Television::Submit(u32 xfb_address, u32 stride, u32 width, u32 height) { m_current_address = xfb_address; m_current_width = width; m_current_height = height; // Load data from GameCube RAM to YUYV texture #ifdef USE_D3D11 u8* yuyvSrc = Memory::GetPointer(xfbAddr); D3D11_BOX box = CD3D11_BOX(0, 0, 0, stride, height, 1); D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2 * stride, 2 * stride * height); #endif }
void D3D11CommandBuffer::CopyBuffer(Buffer& dstBuffer, std::uint64_t dstOffset, Buffer& srcBuffer, std::uint64_t srcOffset, std::uint64_t size) { auto& dstBufferD3D = LLGL_CAST(D3D11Buffer&, dstBuffer); auto& srcBufferD3D = LLGL_CAST(D3D11Buffer&, srcBuffer); context_->CopySubresourceRegion( dstBufferD3D.GetNative(), // pDstResource 0, // DstSubresource static_cast<UINT>(dstOffset), // DstX 0, // DstY 0, // DstZ srcBufferD3D.GetNative(), // pSrcResource 0, // SrcSubresource &CD3D11_BOX( // pSrcBox static_cast<LONG>(srcOffset), 0, 0, static_cast<LONG>(srcOffset + size), 1, 1 ) ); }
void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage) { if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING) { D3D11_MAPPED_SUBRESOURCE map; D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map); if (4 * pitch == map.RowPitch) { memcpy(map.pData, buffer, map.RowPitch * height); } else { for (unsigned int y = 0; y < height; ++y) memcpy((u8*)map.pData + y * map.RowPitch, (u32*)buffer + y * pitch, 4 * pitch); } D3D::context->Unmap(pTexture, level); } else { D3D11_BOX dest_region = CD3D11_BOX(0, 0, 0, width, height, 1); D3D::context->UpdateSubresource(pTexture, level, &dest_region, buffer, 4*pitch, 4*pitch*height); } }
void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma) { HRESULT hr; // Reset API g_renderer->ResetAPIState(); // Set up all the state for XFB encoding D3D::stateman->SetPixelShader(m_pShader); D3D::stateman->SetVertexShader(m_vShader); D3D::stateman->SetGeometryShader(nullptr); D3D::stateman->PushBlendState(m_xfbEncodeBlendState); D3D::stateman->PushDepthState(m_xfbEncodeDepthState); D3D::stateman->PushRasterizerState(m_xfbEncodeRastState); D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(width/4), FLOAT(height)); D3D::context->RSSetViewports(1, &vp); D3D::stateman->SetInputLayout(m_quadLayout); D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); UINT stride = sizeof(QuadVertex); UINT offset = 0; D3D::stateman->SetVertexBuffer(m_quad, stride, offset); TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(srcRect); XFBEncodeParams params = { 0 }; params.Width = FLOAT(width/2); params.Height = FLOAT(height); params.TexLeft = FLOAT(targetRect.left) / g_renderer->GetTargetWidth(); params.TexTop = FLOAT(targetRect.top) / g_renderer->GetTargetHeight(); params.TexRight = FLOAT(targetRect.right) / g_renderer->GetTargetWidth(); params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetTargetHeight(); params.Gamma = gamma; D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, ¶ms, 0, 0); D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr); ID3D11ShaderResourceView* pEFB = FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); D3D::stateman->SetVertexConstants(m_encodeParams); D3D::stateman->SetPixelConstants(m_encodeParams); D3D::stateman->SetTexture(0, pEFB); D3D::stateman->SetSampler(0, m_efbSampler); // Encode! D3D::stateman->Apply(); D3D::context->Draw(4, 0); // Copy to staging buffer D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, width/4, height, 1); D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox); // Clean up state D3D::context->OMSetRenderTargets(0, nullptr, nullptr); D3D::stateman->SetSampler(0, nullptr); D3D::stateman->SetTexture(0, nullptr); D3D::stateman->SetPixelConstants(nullptr); D3D::stateman->SetVertexConstants(nullptr); D3D::stateman->SetPixelShader(nullptr); D3D::stateman->SetVertexShader(nullptr); D3D::stateman->PopRasterizerState(); D3D::stateman->PopDepthState(); D3D::stateman->PopBlendState(); // 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"); u8* src = (u8*)map.pData; for (unsigned int y = 0; y < height; ++y) { memcpy(dst, src, width); dst += bpmem.copyMipMapStrideChannels*32; src += map.RowPitch; } D3D::context->Unmap(m_outStage, 0); // Restore API g_renderer->RestoreAPIState(); D3D::stateman->Apply(); // force unbind efb texture as shader resource D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); }
size_t PSTextureEncoder::Encode(u8* dst, unsigned int dstFormat, PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf) { if (!m_ready) // Make sure we initialized OK return 0; // Clamp srcRect to 640x528. BPS: The Strike tries to encode an 800x600 // texture, which is invalid. EFBRectangle correctSrc = srcRect; correctSrc.ClampUL(0, 0, EFB_WIDTH, EFB_HEIGHT); // Validate source rect size if (correctSrc.GetWidth() <= 0 || correctSrc.GetHeight() <= 0) return 0; HRESULT hr; unsigned int blockW = BLOCK_WIDTHS[dstFormat]; unsigned int blockH = BLOCK_HEIGHTS[dstFormat]; // Round up source dims to multiple of block size unsigned int actualWidth = correctSrc.GetWidth() / (scaleByHalf ? 2 : 1); actualWidth = (actualWidth + blockW-1) & ~(blockW-1); unsigned int actualHeight = correctSrc.GetHeight() / (scaleByHalf ? 2 : 1); actualHeight = (actualHeight + blockH-1) & ~(blockH-1); unsigned int numBlocksX = actualWidth/blockW; unsigned int numBlocksY = actualHeight/blockH; unsigned int cacheLinesPerRow; if (dstFormat == 0x6) // RGBA takes two cache lines per block; all others take one cacheLinesPerRow = numBlocksX*2; else cacheLinesPerRow = numBlocksX; _assert_msg_(VIDEO, cacheLinesPerRow*32 <= MAX_BYTES_PER_BLOCK_ROW, "cache lines per row sanity check"); unsigned int totalCacheLines = cacheLinesPerRow * numBlocksY; _assert_msg_(VIDEO, totalCacheLines*32 <= MAX_BYTES_PER_ENCODE, "total encode size sanity check"); size_t encodeSize = 0; // Reset API g_renderer->ResetAPIState(); // Set up all the state for EFB encoding { D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(cacheLinesPerRow * 8), FLOAT(numBlocksY)); D3D::context->RSSetViewports(1, &vp); EFBRectangle fullSrcRect; fullSrcRect.left = 0; fullSrcRect.top = 0; fullSrcRect.right = EFB_WIDTH; fullSrcRect.bottom = EFB_HEIGHT; TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(fullSrcRect); D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr); ID3D11ShaderResourceView* pEFB = (srcFormat == PEControl::Z24) ? FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() : // 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. FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); EFBEncodeParams params; params.SrcLeft = correctSrc.left; params.SrcTop = correctSrc.top; params.DestWidth = actualWidth; params.ScaleFactor = scaleByHalf ? 2 : 1; D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, ¶ms, 0, 0); D3D::stateman->SetPixelConstants(m_encodeParams); // Use linear filtering if (bScaleByHalf), use point filtering otherwise if (scaleByHalf) D3D::SetLinearCopySampler(); else D3D::SetPointCopySampler(); D3D::drawShadedTexQuad(pEFB, targetRect.AsRECT(), Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), SetStaticShader(dstFormat, srcFormat, isIntensity, scaleByHalf), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout()); // Copy to staging buffer D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, cacheLinesPerRow * 8, numBlocksY, 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; for (unsigned int y = 0; y < numBlocksY; ++y) { memcpy(dst, src, cacheLinesPerRow*32); dst += bpmem.copyMipMapStrideChannels*32; src += map.RowPitch; } D3D::context->Unmap(m_outStage, 0); encodeSize = bpmem.copyMipMapStrideChannels*32 * numBlocksY; } // Restore API g_renderer->RestoreAPIState(); D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); return encodeSize; }
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()); }