diff options
| author | Pierre Bourdon <delroth@gmail.com> | 2016-06-24 10:43:46 +0200 |
|---|---|---|
| committer | Pierre Bourdon <delroth@gmail.com> | 2016-06-24 10:43:46 +0200 |
| commit | 3570c7f03a2aa90aa634f96c0af1969af610f14d (patch) | |
| tree | 4252e03c0e853ba7cffe022937698c854ad0eaa9 /Source/Core/VideoBackends/D3D/Render.cpp | |
| parent | 2115e8a4a6814e32107b5205ff5c95bbd3c6e99c (diff) | |
Reformat all the things. Have fun with merge conflicts.
Diffstat (limited to 'Source/Core/VideoBackends/D3D/Render.cpp')
| -rw-r--r-- | Source/Core/VideoBackends/D3D/Render.cpp | 2263 |
1 files changed, 1170 insertions, 1093 deletions
diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index c5f591bd30..a18538e234 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -41,7 +41,6 @@ namespace DX11 { - static u32 s_last_multisamples = 1; static bool s_last_stereo_mode = false; static bool s_last_xfb_mode = false; @@ -60,11 +59,11 @@ static D3DTexture2D* s_3d_vision_texture = nullptr; // Nvidia stereo blitting struct defined in "nvstereo.h" from the Nvidia SDK typedef struct _Nv_Stereo_Image_Header { - unsigned int dwSignature; - unsigned int dwWidth; - unsigned int dwHeight; - unsigned int dwBPP; - unsigned int dwFlags; + unsigned int dwSignature; + unsigned int dwWidth; + unsigned int dwHeight; + unsigned int dwBPP; + unsigned int dwFlags; } NVSTEREOIMAGEHEADER, *LPNVSTEREOIMAGEHEADER; #define NVSTEREO_IMAGE_SIGNATURE 0x4433564e @@ -72,10 +71,10 @@ typedef struct _Nv_Stereo_Image_Header // GX pipeline state struct { - SamplerState sampler[8]; - BlendState blend; - ZMode zmode; - RasterizerState raster; + SamplerState sampler[8]; + BlendState blend; + ZMode zmode; + RasterizerState raster; } gx_state; @@ -83,260 +82,277 @@ StateCache gx_state_cache; static void SetupDeviceObjects() { - s_television.Init(); - - g_framebuffer_manager = std::make_unique<FramebufferManager>(); - - HRESULT hr; - - D3D11_DEPTH_STENCIL_DESC ddesc; - ddesc.DepthEnable = FALSE; - ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - ddesc.DepthFunc = D3D11_COMPARISON_ALWAYS; - ddesc.StencilEnable = FALSE; - ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[0]); - CHECK(hr==S_OK, "Create depth state for Renderer::ClearScreen"); - ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; - ddesc.DepthEnable = TRUE; - hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[1]); - CHECK(hr==S_OK, "Create depth state for Renderer::ClearScreen"); - ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[2]); - CHECK(hr==S_OK, "Create depth state for Renderer::ClearScreen"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)cleardepthstates[0], "depth state for Renderer::ClearScreen (depth buffer disabled)"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)cleardepthstates[1], "depth state for Renderer::ClearScreen (depth buffer enabled, writing enabled)"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)cleardepthstates[2], "depth state for Renderer::ClearScreen (depth buffer enabled, writing disabled)"); - - D3D11_BLEND_DESC blenddesc; - blenddesc.AlphaToCoverageEnable = FALSE; - blenddesc.IndependentBlendEnable = FALSE; - blenddesc.RenderTarget[0].BlendEnable = FALSE; - blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; - blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; - blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; - blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - hr = D3D::device->CreateBlendState(&blenddesc, &resetblendstate); - CHECK(hr==S_OK, "Create blend state for Renderer::ResetAPIState"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)resetblendstate, "blend state for Renderer::ResetAPIState"); - - clearblendstates[0] = resetblendstate; - resetblendstate->AddRef(); - - blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_RED|D3D11_COLOR_WRITE_ENABLE_GREEN|D3D11_COLOR_WRITE_ENABLE_BLUE; - hr = D3D::device->CreateBlendState(&blenddesc, &clearblendstates[1]); - CHECK(hr==S_OK, "Create blend state for Renderer::ClearScreen"); - - blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA; - hr = D3D::device->CreateBlendState(&blenddesc, &clearblendstates[2]); - CHECK(hr==S_OK, "Create blend state for Renderer::ClearScreen"); - - blenddesc.RenderTarget[0].RenderTargetWriteMask = 0; - hr = D3D::device->CreateBlendState(&blenddesc, &clearblendstates[3]); - CHECK(hr==S_OK, "Create blend state for Renderer::ClearScreen"); - - ddesc.DepthEnable = FALSE; - ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; - ddesc.DepthFunc = D3D11_COMPARISON_LESS; - ddesc.StencilEnable = FALSE; - ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; - ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; - hr = D3D::device->CreateDepthStencilState(&ddesc, &resetdepthstate); - CHECK(hr==S_OK, "Create depth state for Renderer::ResetAPIState"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)resetdepthstate, "depth stencil state for Renderer::ResetAPIState"); - - D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, 0, 0.f, 0.f, false, false, false, false); - hr = D3D::device->CreateRasterizerState(&rastdesc, &resetraststate); - CHECK(hr==S_OK, "Create rasterizer state for Renderer::ResetAPIState"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)resetraststate, "rasterizer state for Renderer::ResetAPIState"); - - s_screenshot_texture = nullptr; + s_television.Init(); + + g_framebuffer_manager = std::make_unique<FramebufferManager>(); + + HRESULT hr; + + D3D11_DEPTH_STENCIL_DESC ddesc; + ddesc.DepthEnable = FALSE; + ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + ddesc.DepthFunc = D3D11_COMPARISON_ALWAYS; + ddesc.StencilEnable = FALSE; + ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[0]); + CHECK(hr == S_OK, "Create depth state for Renderer::ClearScreen"); + ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + ddesc.DepthEnable = TRUE; + hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[1]); + CHECK(hr == S_OK, "Create depth state for Renderer::ClearScreen"); + ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + hr = D3D::device->CreateDepthStencilState(&ddesc, &cleardepthstates[2]); + CHECK(hr == S_OK, "Create depth state for Renderer::ClearScreen"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)cleardepthstates[0], + "depth state for Renderer::ClearScreen (depth buffer disabled)"); + D3D::SetDebugObjectName( + (ID3D11DeviceChild*)cleardepthstates[1], + "depth state for Renderer::ClearScreen (depth buffer enabled, writing enabled)"); + D3D::SetDebugObjectName( + (ID3D11DeviceChild*)cleardepthstates[2], + "depth state for Renderer::ClearScreen (depth buffer enabled, writing disabled)"); + + D3D11_BLEND_DESC blenddesc; + blenddesc.AlphaToCoverageEnable = FALSE; + blenddesc.IndependentBlendEnable = FALSE; + blenddesc.RenderTarget[0].BlendEnable = FALSE; + blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; + blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; + blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + hr = D3D::device->CreateBlendState(&blenddesc, &resetblendstate); + CHECK(hr == S_OK, "Create blend state for Renderer::ResetAPIState"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)resetblendstate, + "blend state for Renderer::ResetAPIState"); + + clearblendstates[0] = resetblendstate; + resetblendstate->AddRef(); + + blenddesc.RenderTarget[0].RenderTargetWriteMask = + D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE; + hr = D3D::device->CreateBlendState(&blenddesc, &clearblendstates[1]); + CHECK(hr == S_OK, "Create blend state for Renderer::ClearScreen"); + + blenddesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALPHA; + hr = D3D::device->CreateBlendState(&blenddesc, &clearblendstates[2]); + CHECK(hr == S_OK, "Create blend state for Renderer::ClearScreen"); + + blenddesc.RenderTarget[0].RenderTargetWriteMask = 0; + hr = D3D::device->CreateBlendState(&blenddesc, &clearblendstates[3]); + CHECK(hr == S_OK, "Create blend state for Renderer::ClearScreen"); + + ddesc.DepthEnable = FALSE; + ddesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; + ddesc.DepthFunc = D3D11_COMPARISON_LESS; + ddesc.StencilEnable = FALSE; + ddesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; + ddesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + hr = D3D::device->CreateDepthStencilState(&ddesc, &resetdepthstate); + CHECK(hr == S_OK, "Create depth state for Renderer::ResetAPIState"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)resetdepthstate, + "depth stencil state for Renderer::ResetAPIState"); + + D3D11_RASTERIZER_DESC rastdesc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, D3D11_CULL_NONE, false, + 0, 0.f, 0.f, false, false, false, false); + hr = D3D::device->CreateRasterizerState(&rastdesc, &resetraststate); + CHECK(hr == S_OK, "Create rasterizer state for Renderer::ResetAPIState"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)resetraststate, + "rasterizer state for Renderer::ResetAPIState"); + + s_screenshot_texture = nullptr; } // Kill off all device objects static void TeardownDeviceObjects() { - g_framebuffer_manager.reset(); - - SAFE_RELEASE(clearblendstates[0]); - SAFE_RELEASE(clearblendstates[1]); - SAFE_RELEASE(clearblendstates[2]); - SAFE_RELEASE(clearblendstates[3]); - SAFE_RELEASE(cleardepthstates[0]); - SAFE_RELEASE(cleardepthstates[1]); - SAFE_RELEASE(cleardepthstates[2]); - SAFE_RELEASE(resetblendstate); - SAFE_RELEASE(resetdepthstate); - SAFE_RELEASE(resetraststate); - SAFE_RELEASE(s_screenshot_texture); - SAFE_RELEASE(s_3d_vision_texture); - - s_television.Shutdown(); - - gx_state_cache.Clear(); + g_framebuffer_manager.reset(); + + SAFE_RELEASE(clearblendstates[0]); + SAFE_RELEASE(clearblendstates[1]); + SAFE_RELEASE(clearblendstates[2]); + SAFE_RELEASE(clearblendstates[3]); + SAFE_RELEASE(cleardepthstates[0]); + SAFE_RELEASE(cleardepthstates[1]); + SAFE_RELEASE(cleardepthstates[2]); + SAFE_RELEASE(resetblendstate); + SAFE_RELEASE(resetdepthstate); + SAFE_RELEASE(resetraststate); + SAFE_RELEASE(s_screenshot_texture); + SAFE_RELEASE(s_3d_vision_texture); + + s_television.Shutdown(); + + gx_state_cache.Clear(); } static void CreateScreenshotTexture() { - // We can't render anything outside of the backbuffer anyway, so use the backbuffer size as the screenshot buffer size. - // This texture is released to be recreated when the window is resized in Renderer::SwapImpl. - D3D11_TEXTURE2D_DESC scrtex_desc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, D3D::GetBackBufferWidth(), D3D::GetBackBufferHeight(), 1, 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ|D3D11_CPU_ACCESS_WRITE); - HRESULT hr = D3D::device->CreateTexture2D(&scrtex_desc, nullptr, &s_screenshot_texture); - CHECK(hr==S_OK, "Create screenshot staging texture"); - D3D::SetDebugObjectName((ID3D11DeviceChild*)s_screenshot_texture, "staging screenshot texture"); + // We can't render anything outside of the backbuffer anyway, so use the backbuffer size as the + // screenshot buffer size. + // This texture is released to be recreated when the window is resized in Renderer::SwapImpl. + D3D11_TEXTURE2D_DESC scrtex_desc = CD3D11_TEXTURE2D_DESC( + DXGI_FORMAT_R8G8B8A8_UNORM, D3D::GetBackBufferWidth(), D3D::GetBackBufferHeight(), 1, 1, 0, + D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE); + HRESULT hr = D3D::device->CreateTexture2D(&scrtex_desc, nullptr, &s_screenshot_texture); + CHECK(hr == S_OK, "Create screenshot staging texture"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_screenshot_texture, "staging screenshot texture"); } static D3D11_BOX GetScreenshotSourceBox(const TargetRectangle& targetRc) { - // Since the screenshot buffer is copied back to the CPU via Map(), we can't access pixels that - // fall outside the backbuffer bounds. Therefore, when crop is enabled and the target rect is - // off-screen to the top/left, we clamp the origin at zero, as well as the bottom/right - // coordinates at the backbuffer dimensions. This will result in a rectangle that can be - // smaller than the backbuffer, but never larger. - return CD3D11_BOX( - std::max(targetRc.left, 0), - std::max(targetRc.top, 0), - 0, - std::min(D3D::GetBackBufferWidth(), (unsigned int)targetRc.right), - std::min(D3D::GetBackBufferHeight(), (unsigned int)targetRc.bottom), - 1); + // Since the screenshot buffer is copied back to the CPU via Map(), we can't access pixels that + // fall outside the backbuffer bounds. Therefore, when crop is enabled and the target rect is + // off-screen to the top/left, we clamp the origin at zero, as well as the bottom/right + // coordinates at the backbuffer dimensions. This will result in a rectangle that can be + // smaller than the backbuffer, but never larger. + return CD3D11_BOX(std::max(targetRc.left, 0), std::max(targetRc.top, 0), 0, + std::min(D3D::GetBackBufferWidth(), (unsigned int)targetRc.right), + std::min(D3D::GetBackBufferHeight(), (unsigned int)targetRc.bottom), 1); } static void Create3DVisionTexture(int width, int height) { - // Create a staging texture for 3D vision with signature information in the last row. - // Nvidia 3D Vision supports full SBS, so there is no loss in resolution during this process. - D3D11_SUBRESOURCE_DATA sysData; - sysData.SysMemPitch = 4 * width * 2; - sysData.pSysMem = new u8[(height + 1) * sysData.SysMemPitch]; - LPNVSTEREOIMAGEHEADER header = (LPNVSTEREOIMAGEHEADER)((u8*)sysData.pSysMem + height * sysData.SysMemPitch); - header->dwSignature = NVSTEREO_IMAGE_SIGNATURE; - header->dwWidth = width * 2; - header->dwHeight = height + 1; - header->dwBPP = 32; - header->dwFlags = 0; - - s_3d_vision_texture = D3DTexture2D::Create(width * 2, height + 1, D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, &sysData); - delete[] sysData.pSysMem; + // Create a staging texture for 3D vision with signature information in the last row. + // Nvidia 3D Vision supports full SBS, so there is no loss in resolution during this process. + D3D11_SUBRESOURCE_DATA sysData; + sysData.SysMemPitch = 4 * width * 2; + sysData.pSysMem = new u8[(height + 1) * sysData.SysMemPitch]; + LPNVSTEREOIMAGEHEADER header = + (LPNVSTEREOIMAGEHEADER)((u8*)sysData.pSysMem + height * sysData.SysMemPitch); + header->dwSignature = NVSTEREO_IMAGE_SIGNATURE; + header->dwWidth = width * 2; + header->dwHeight = height + 1; + header->dwBPP = 32; + header->dwFlags = 0; + + s_3d_vision_texture = + D3DTexture2D::Create(width * 2, height + 1, D3D11_BIND_RENDER_TARGET, D3D11_USAGE_DEFAULT, + DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, &sysData); + delete[] sysData.pSysMem; } -Renderer::Renderer(void *&window_handle) +Renderer::Renderer(void*& window_handle) { - D3D::Create((HWND)window_handle); - - s_backbuffer_width = D3D::GetBackBufferWidth(); - s_backbuffer_height = D3D::GetBackBufferHeight(); - - FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH); - FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT); - - UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); - - s_last_multisamples = g_ActiveConfig.iMultisamples; - s_last_efb_scale = g_ActiveConfig.iEFBScale; - s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; - s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; - CalculateTargetSize(s_backbuffer_width, s_backbuffer_height); - PixelShaderManager::SetEfbScaleChanged(); - - SetupDeviceObjects(); - - // Setup GX pipeline state - gx_state.blend.blend_enable = false; - gx_state.blend.write_mask = D3D11_COLOR_WRITE_ENABLE_ALL; - gx_state.blend.src_blend = D3D11_BLEND_ONE; - gx_state.blend.dst_blend = D3D11_BLEND_ZERO; - gx_state.blend.blend_op = D3D11_BLEND_OP_ADD; - gx_state.blend.use_dst_alpha = false; - - for (unsigned int k = 0;k < 8;k++) - { - gx_state.sampler[k].packed = 0; - } - - gx_state.zmode.testenable = false; - gx_state.zmode.updateenable = false; - gx_state.zmode.func = ZMode::NEVER; - - gx_state.raster.cull_mode = D3D11_CULL_NONE; - - // Clear EFB textures - float ClearColor[4] = { 0.f, 0.f, 0.f, 1.f }; - D3D::context->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV(), ClearColor); - D3D::context->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV(), D3D11_CLEAR_DEPTH, 0.f, 0); - - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)s_target_width, (float)s_target_height); - D3D::context->RSSetViewports(1, &vp); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); - D3D::BeginFrame(); + D3D::Create((HWND)window_handle); + + s_backbuffer_width = D3D::GetBackBufferWidth(); + s_backbuffer_height = D3D::GetBackBufferHeight(); + + FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH); + FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT); + + UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); + + s_last_multisamples = g_ActiveConfig.iMultisamples; + s_last_efb_scale = g_ActiveConfig.iEFBScale; + s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; + s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; + CalculateTargetSize(s_backbuffer_width, s_backbuffer_height); + PixelShaderManager::SetEfbScaleChanged(); + + SetupDeviceObjects(); + + // Setup GX pipeline state + gx_state.blend.blend_enable = false; + gx_state.blend.write_mask = D3D11_COLOR_WRITE_ENABLE_ALL; + gx_state.blend.src_blend = D3D11_BLEND_ONE; + gx_state.blend.dst_blend = D3D11_BLEND_ZERO; + gx_state.blend.blend_op = D3D11_BLEND_OP_ADD; + gx_state.blend.use_dst_alpha = false; + + for (unsigned int k = 0; k < 8; k++) + { + gx_state.sampler[k].packed = 0; + } + + gx_state.zmode.testenable = false; + gx_state.zmode.updateenable = false; + gx_state.zmode.func = ZMode::NEVER; + + gx_state.raster.cull_mode = D3D11_CULL_NONE; + + // Clear EFB textures + float ClearColor[4] = {0.f, 0.f, 0.f, 1.f}; + D3D::context->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV(), + ClearColor); + D3D::context->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV(), + D3D11_CLEAR_DEPTH, 0.f, 0); + + D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)s_target_width, (float)s_target_height); + D3D::context->RSSetViewports(1, &vp); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); + D3D::BeginFrame(); } Renderer::~Renderer() { - TeardownDeviceObjects(); - D3D::EndFrame(); - D3D::Present(); - D3D::Close(); + TeardownDeviceObjects(); + D3D::EndFrame(); + D3D::Present(); + D3D::Close(); } void Renderer::RenderText(const std::string& text, int left, int top, u32 color) { - D3D::font.DrawTextScaled((float)(left+1), (float)(top+1), 20.f, 0.0f, color & 0xFF000000, text); - D3D::font.DrawTextScaled((float)left, (float)top, 20.f, 0.0f, color, text); + D3D::font.DrawTextScaled((float)(left + 1), (float)(top + 1), 20.f, 0.0f, color & 0xFF000000, + text); + D3D::font.DrawTextScaled((float)left, (float)top, 20.f, 0.0f, color, text); } TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc) { - TargetRectangle result; - result.left = EFBToScaledX(rc.left); - result.top = EFBToScaledY(rc.top); - result.right = EFBToScaledX(rc.right); - result.bottom = EFBToScaledY(rc.bottom); - return result; + TargetRectangle result; + result.left = EFBToScaledX(rc.left); + result.top = EFBToScaledY(rc.top); + result.right = EFBToScaledX(rc.right); + result.bottom = EFBToScaledY(rc.bottom); + return result; } // With D3D, we have to resize the backbuffer if the window changed // size. bool Renderer::CheckForResize() { - RECT rcWindow; - GetClientRect(D3D::hWnd, &rcWindow); - int client_width = rcWindow.right - rcWindow.left; - int client_height = rcWindow.bottom - rcWindow.top; - - // Sanity check - if ((client_width != Renderer::GetBackbufferWidth() || - client_height != Renderer::GetBackbufferHeight()) && - client_width >= 4 && client_height >= 4) - { - return true; - } - - return false; + RECT rcWindow; + GetClientRect(D3D::hWnd, &rcWindow); + int client_width = rcWindow.right - rcWindow.left; + int client_height = rcWindow.bottom - rcWindow.top; + + // Sanity check + if ((client_width != Renderer::GetBackbufferWidth() || + client_height != Renderer::GetBackbufferHeight()) && + client_width >= 4 && client_height >= 4) + { + return true; + } + + return false; } void Renderer::SetScissorRect(const EFBRectangle& rc) { - TargetRectangle trc = ConvertEFBRectangle(rc); - D3D::context->RSSetScissorRects(1, trc.AsRECT()); + TargetRectangle trc = ConvertEFBRectangle(rc); + D3D::context->RSSetScissorRects(1, trc.AsRECT()); } void Renderer::SetColorMask() { - // Only enable alpha channel if it's supported by the current EFB format - UINT8 color_mask = 0; - if (bpmem.alpha_test.TestResult() != AlphaTest::FAIL) - { - if (bpmem.blendmode.alphaupdate && (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24)) - color_mask = D3D11_COLOR_WRITE_ENABLE_ALPHA; - if (bpmem.blendmode.colorupdate) - color_mask |= D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE; - } - gx_state.blend.write_mask = color_mask; + // Only enable alpha channel if it's supported by the current EFB format + UINT8 color_mask = 0; + if (bpmem.alpha_test.TestResult() != AlphaTest::FAIL) + { + if (bpmem.blendmode.alphaupdate && (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24)) + color_mask = D3D11_COLOR_WRITE_ENABLE_ALPHA; + if (bpmem.blendmode.colorupdate) + color_mask |= D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | + D3D11_COLOR_WRITE_ENABLE_BLUE; + } + gx_state.blend.write_mask = color_mask; } // This function allows the CPU to directly access the EFB. @@ -355,976 +371,1037 @@ void Renderer::SetColorMask() // - GX_PokeZMode (TODO) u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) { - // Convert EFB dimensions to the ones of our render target - EFBRectangle efbPixelRc; - efbPixelRc.left = x; - efbPixelRc.top = y; - efbPixelRc.right = x + 1; - efbPixelRc.bottom = y + 1; - TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc); - - // Take the mean of the resulting dimensions; TODO: Don't use the center pixel, compute the average color instead - D3D11_RECT RectToLock; - if (type == PEEK_COLOR || type == PEEK_Z) - { - RectToLock.left = (targetPixelRc.left + targetPixelRc.right) / 2; - RectToLock.top = (targetPixelRc.top + targetPixelRc.bottom) / 2; - RectToLock.right = RectToLock.left + 1; - RectToLock.bottom = RectToLock.top + 1; - } - else - { - RectToLock.left = targetPixelRc.left; - RectToLock.right = targetPixelRc.right; - RectToLock.top = targetPixelRc.top; - RectToLock.bottom = targetPixelRc.bottom; - } - - // Reset any game specific settings. - ResetAPIState(); - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, 1.f, 1.f); - D3D::context->RSSetViewports(1, &vp); - D3D::SetPointCopySampler(); - - // Select copy and read textures depending on if we are doing a color or depth read (since they are different formats). - D3DTexture2D* source_tex; - D3DTexture2D* read_tex; - ID3D11Texture2D* staging_tex; - if (type == PEEK_COLOR) - { - source_tex = FramebufferManager::GetEFBColorTexture(); - read_tex = FramebufferManager::GetEFBColorReadTexture(); - staging_tex = FramebufferManager::GetEFBColorStagingBuffer(); - } - else - { - source_tex = FramebufferManager::GetEFBDepthTexture(); - read_tex = FramebufferManager::GetEFBDepthReadTexture(); - staging_tex = FramebufferManager::GetEFBDepthStagingBuffer(); - } - - // Select pixel shader (we don't want to average depth samples, instead select the minimum). - ID3D11PixelShader* copy_pixel_shader; - if (type == PEEK_Z && g_ActiveConfig.iMultisamples > 1) - copy_pixel_shader = PixelShaderCache::GetDepthResolveProgram(); - else - copy_pixel_shader = PixelShaderCache::GetColorCopyProgram(true); - - // Draw a quad to grab the texel we want to read. - D3D::context->OMSetRenderTargets(1, &read_tex->GetRTV(), nullptr); - D3D::drawShadedTexQuad(source_tex->GetSRV(), - &RectToLock, - Renderer::GetTargetWidth(), - Renderer::GetTargetHeight(), - copy_pixel_shader, - VertexShaderCache::GetSimpleVertexShader(), - VertexShaderCache::GetSimpleInputLayout()); - - // Restore expected game state. - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); - RestoreAPIState(); - - // Copy the pixel from the renderable to cpu-readable buffer. - D3D11_BOX box = CD3D11_BOX(0, 0, 0, 1, 1, 1); - D3D::context->CopySubresourceRegion(staging_tex, 0, 0, 0, 0, read_tex->GetTex(), 0, &box); - D3D11_MAPPED_SUBRESOURCE map; - CHECK(D3D::context->Map(staging_tex, 0, D3D11_MAP_READ, 0, &map) == S_OK, "Map staging buffer failed"); - - // Convert the framebuffer data to the format the game is expecting to receive. - u32 ret; - if (type == PEEK_COLOR) - { - u32 val; - memcpy(&val, map.pData, sizeof(val)); - - // our buffers are RGBA, yet a BGRA value is expected - val = ((val & 0xFF00FF00) | ((val >> 16) & 0xFF) | ((val << 16) & 0xFF0000)); - - // check what to do with the alpha channel (GX_PokeAlphaRead) - PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode(); - - if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24) - { - val = RGBA8ToRGBA6ToRGBA8(val); - } - else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) - { - val = RGBA8ToRGB565ToRGBA8(val); - } - if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24) - { - val |= 0xFF000000; - } - - if (alpha_read_mode.ReadMode == 2) ret = val; // GX_READ_NONE - else if (alpha_read_mode.ReadMode == 1) ret = (val | 0xFF000000); // GX_READ_FF - else /*if(alpha_read_mode.ReadMode == 0)*/ ret = (val & 0x00FFFFFF); // GX_READ_00 - } - else // type == PEEK_Z - { - float val; - memcpy(&val, map.pData, sizeof(val)); - - // depth buffer is inverted in the d3d backend - val = 1.0f - val; - - if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) - { - // if Z is in 16 bit format you must return a 16 bit integer - ret = MathUtil::Clamp<u32>(static_cast<u32>(val * 65536.0f), 0, 0xFFFF); - } - else - { - ret = MathUtil::Clamp<u32>(static_cast<u32>(val * 16777216.0f), 0, 0xFFFFFF); - } - } - - D3D::context->Unmap(staging_tex, 0); - return ret; + // Convert EFB dimensions to the ones of our render target + EFBRectangle efbPixelRc; + efbPixelRc.left = x; + efbPixelRc.top = y; + efbPixelRc.right = x + 1; + efbPixelRc.bottom = y + 1; + TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc); + + // Take the mean of the resulting dimensions; TODO: Don't use the center pixel, compute the + // average color instead + D3D11_RECT RectToLock; + if (type == PEEK_COLOR || type == PEEK_Z) + { + RectToLock.left = (targetPixelRc.left + targetPixelRc.right) / 2; + RectToLock.top = (targetPixelRc.top + targetPixelRc.bottom) / 2; + RectToLock.right = RectToLock.left + 1; + RectToLock.bottom = RectToLock.top + 1; + } + else + { + RectToLock.left = targetPixelRc.left; + RectToLock.right = targetPixelRc.right; + RectToLock.top = targetPixelRc.top; + RectToLock.bottom = targetPixelRc.bottom; + } + + // Reset any game specific settings. + ResetAPIState(); + D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, 1.f, 1.f); + D3D::context->RSSetViewports(1, &vp); + D3D::SetPointCopySampler(); + + // Select copy and read textures depending on if we are doing a color or depth read (since they + // are different formats). + D3DTexture2D* source_tex; + D3DTexture2D* read_tex; + ID3D11Texture2D* staging_tex; + if (type == PEEK_COLOR) + { + source_tex = FramebufferManager::GetEFBColorTexture(); + read_tex = FramebufferManager::GetEFBColorReadTexture(); + staging_tex = FramebufferManager::GetEFBColorStagingBuffer(); + } + else + { + source_tex = FramebufferManager::GetEFBDepthTexture(); + read_tex = FramebufferManager::GetEFBDepthReadTexture(); + staging_tex = FramebufferManager::GetEFBDepthStagingBuffer(); + } + + // Select pixel shader (we don't want to average depth samples, instead select the minimum). + ID3D11PixelShader* copy_pixel_shader; + if (type == PEEK_Z && g_ActiveConfig.iMultisamples > 1) + copy_pixel_shader = PixelShaderCache::GetDepthResolveProgram(); + else + copy_pixel_shader = PixelShaderCache::GetColorCopyProgram(true); + + // Draw a quad to grab the texel we want to read. + D3D::context->OMSetRenderTargets(1, &read_tex->GetRTV(), nullptr); + D3D::drawShadedTexQuad(source_tex->GetSRV(), &RectToLock, Renderer::GetTargetWidth(), + Renderer::GetTargetHeight(), copy_pixel_shader, + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout()); + + // Restore expected game state. + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); + RestoreAPIState(); + + // Copy the pixel from the renderable to cpu-readable buffer. + D3D11_BOX box = CD3D11_BOX(0, 0, 0, 1, 1, 1); + D3D::context->CopySubresourceRegion(staging_tex, 0, 0, 0, 0, read_tex->GetTex(), 0, &box); + D3D11_MAPPED_SUBRESOURCE map; + CHECK(D3D::context->Map(staging_tex, 0, D3D11_MAP_READ, 0, &map) == S_OK, + "Map staging buffer failed"); + + // Convert the framebuffer data to the format the game is expecting to receive. + u32 ret; + if (type == PEEK_COLOR) + { + u32 val; + memcpy(&val, map.pData, sizeof(val)); + + // our buffers are RGBA, yet a BGRA value is expected + val = ((val & 0xFF00FF00) | ((val >> 16) & 0xFF) | ((val << 16) & 0xFF0000)); + + // check what to do with the alpha channel (GX_PokeAlphaRead) + PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode(); + + if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24) + { + val = RGBA8ToRGBA6ToRGBA8(val); + } + else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) + { + val = RGBA8ToRGB565ToRGBA8(val); + } + if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24) + { + val |= 0xFF000000; + } + + if (alpha_read_mode.ReadMode == 2) + ret = val; // GX_READ_NONE + else if (alpha_read_mode.ReadMode == 1) + ret = (val | 0xFF000000); // GX_READ_FF + else /*if(alpha_read_mode.ReadMode == 0)*/ + ret = (val & 0x00FFFFFF); // GX_READ_00 + } + else // type == PEEK_Z + { + float val; + memcpy(&val, map.pData, sizeof(val)); + + // depth buffer is inverted in the d3d backend + val = 1.0f - val; + + if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) + { + // if Z is in 16 bit format you must return a 16 bit integer + ret = MathUtil::Clamp<u32>(static_cast<u32>(val * 65536.0f), 0, 0xFFFF); + } + else + { + ret = MathUtil::Clamp<u32>(static_cast<u32>(val * 16777216.0f), 0, 0xFFFFFF); + } + } + + D3D::context->Unmap(staging_tex, 0); + return ret; } void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) { - ResetAPIState(); - - if (type == POKE_COLOR) - { - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight()); - D3D::context->RSSetViewports(1, &vp); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), nullptr); - } - else // if (type == POKE_Z) - { - D3D::stateman->PushBlendState(clearblendstates[3]); - D3D::stateman->PushDepthState(cleardepthstates[1]); - - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight()); - - D3D::context->RSSetViewports(1, &vp); - - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); - } - - D3D::DrawEFBPokeQuads(type, points, num_points); - - if (type == POKE_Z) - { - D3D::stateman->PopDepthState(); - D3D::stateman->PopBlendState(); - } - - RestoreAPIState(); + ResetAPIState(); + + if (type == POKE_COLOR) + { + D3D11_VIEWPORT vp = + CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight()); + D3D::context->RSSetViewports(1, &vp); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + nullptr); + } + else // if (type == POKE_Z) + { + D3D::stateman->PushBlendState(clearblendstates[3]); + D3D::stateman->PushDepthState(cleardepthstates[1]); + + D3D11_VIEWPORT vp = + CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetTargetWidth(), (float)GetTargetHeight()); + + D3D::context->RSSetViewports(1, &vp); + + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); + } + + D3D::DrawEFBPokeQuads(type, points, num_points); + + if (type == POKE_Z) + { + D3D::stateman->PopDepthState(); + D3D::stateman->PopBlendState(); + } + + RestoreAPIState(); } void Renderer::SetViewport() { - // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) - // [0] = width/2 - // [1] = height/2 - // [2] = 16777215 * (farz - nearz) - // [3] = xorig + width/2 + 342 - // [4] = yorig + height/2 + 342 - // [5] = 16777215 * farz - - // D3D crashes for zero viewports - if (xfmem.viewport.wd == 0 || xfmem.viewport.ht == 0) - return; - - int scissorXOff = bpmem.scissorOffset.x * 2; - int scissorYOff = bpmem.scissorOffset.y * 2; - - float X = Renderer::EFBToScaledXf(xfmem.viewport.xOrig - xfmem.viewport.wd - scissorXOff); - float Y = Renderer::EFBToScaledYf(xfmem.viewport.yOrig + xfmem.viewport.ht - scissorYOff); - float Wd = Renderer::EFBToScaledXf(2.0f * xfmem.viewport.wd); - float Ht = Renderer::EFBToScaledYf(-2.0f * xfmem.viewport.ht); - if (Wd < 0.0f) - { - X += Wd; - Wd = -Wd; - } - if (Ht < 0.0f) - { - Y += Ht; - Ht = -Ht; - } - - // In D3D, the viewport rectangle must fit within the render target. - X = (X >= 0.f) ? X : 0.f; - Y = (Y >= 0.f) ? Y : 0.f; - Wd = (X + Wd <= GetTargetWidth()) ? Wd : (GetTargetWidth() - X); - Ht = (Y + Ht <= GetTargetHeight()) ? Ht : (GetTargetHeight() - Y); - - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(X, Y, Wd, Ht, - 1.0f - MathUtil::Clamp<float>(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f, - 1.0f - MathUtil::Clamp<float>(xfmem.viewport.farZ - MathUtil::Clamp<float>(xfmem.viewport.zRange, 0.0f, 16777216.0f), 0.0f, 16777215.0f) / 16777216.0f); - D3D::context->RSSetViewports(1, &vp); + // reversed gxsetviewport(xorig, yorig, width, height, nearz, farz) + // [0] = width/2 + // [1] = height/2 + // [2] = 16777215 * (farz - nearz) + // [3] = xorig + width/2 + 342 + // [4] = yorig + height/2 + 342 + // [5] = 16777215 * farz + + // D3D crashes for zero viewports + if (xfmem.viewport.wd == 0 || xfmem.viewport.ht == 0) + return; + + int scissorXOff = bpmem.scissorOffset.x * 2; + int scissorYOff = bpmem.scissorOffset.y * 2; + + float X = Renderer::EFBToScaledXf(xfmem.viewport.xOrig - xfmem.viewport.wd - scissorXOff); + float Y = Renderer::EFBToScaledYf(xfmem.viewport.yOrig + xfmem.viewport.ht - scissorYOff); + float Wd = Renderer::EFBToScaledXf(2.0f * xfmem.viewport.wd); + float Ht = Renderer::EFBToScaledYf(-2.0f * xfmem.viewport.ht); + if (Wd < 0.0f) + { + X += Wd; + Wd = -Wd; + } + if (Ht < 0.0f) + { + Y += Ht; + Ht = -Ht; + } + + // In D3D, the viewport rectangle must fit within the render target. + X = (X >= 0.f) ? X : 0.f; + Y = (Y >= 0.f) ? Y : 0.f; + Wd = (X + Wd <= GetTargetWidth()) ? Wd : (GetTargetWidth() - X); + Ht = (Y + Ht <= GetTargetHeight()) ? Ht : (GetTargetHeight() - Y); + + D3D11_VIEWPORT vp = CD3D11_VIEWPORT( + X, Y, Wd, Ht, + 1.0f - MathUtil::Clamp<float>(xfmem.viewport.farZ, 0.0f, 16777215.0f) / 16777216.0f, + 1.0f - + MathUtil::Clamp<float>(xfmem.viewport.farZ - MathUtil::Clamp<float>(xfmem.viewport.zRange, + 0.0f, 16777216.0f), + 0.0f, 16777215.0f) / + 16777216.0f); + D3D::context->RSSetViewports(1, &vp); } -void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) +void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, + u32 color, u32 z) { - ResetAPIState(); - - if (colorEnable && alphaEnable) D3D::stateman->PushBlendState(clearblendstates[0]); - else if (colorEnable) D3D::stateman->PushBlendState(clearblendstates[1]); - else if (alphaEnable) D3D::stateman->PushBlendState(clearblendstates[2]); - else D3D::stateman->PushBlendState(clearblendstates[3]); - - // TODO: Should we enable Z testing here? - /*if (!bpmem.zmode.testenable) D3D::stateman->PushDepthState(cleardepthstates[0]); - else */if (zEnable) D3D::stateman->PushDepthState(cleardepthstates[1]); - else /*if (!zEnable)*/ D3D::stateman->PushDepthState(cleardepthstates[2]); - - // Update the view port for clearing the picture - TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc); - D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, (float)targetRc.GetWidth(), (float)targetRc.GetHeight(), 0.f, 1.f); - D3D::context->RSSetViewports(1, &vp); - - // Color is passed in bgra mode so we need to convert it to rgba - u32 rgbaColor = (color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000); - D3D::drawClearQuad(rgbaColor, 1.0f - (z & 0xFFFFFF) / 16777216.0f); - - D3D::stateman->PopDepthState(); - D3D::stateman->PopBlendState(); - - RestoreAPIState(); + ResetAPIState(); + + if (colorEnable && alphaEnable) + D3D::stateman->PushBlendState(clearblendstates[0]); + else if (colorEnable) + D3D::stateman->PushBlendState(clearblendstates[1]); + else if (alphaEnable) + D3D::stateman->PushBlendState(clearblendstates[2]); + else + D3D::stateman->PushBlendState(clearblendstates[3]); + + // TODO: Should we enable Z testing here? + /*if (!bpmem.zmode.testenable) D3D::stateman->PushDepthState(cleardepthstates[0]); + else */ if (zEnable) + D3D::stateman->PushDepthState(cleardepthstates[1]); + else /*if (!zEnable)*/ + D3D::stateman->PushDepthState(cleardepthstates[2]); + + // Update the view port for clearing the picture + TargetRectangle targetRc = Renderer::ConvertEFBRectangle(rc); + D3D11_VIEWPORT vp = + CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, (float)targetRc.GetWidth(), + (float)targetRc.GetHeight(), 0.f, 1.f); + D3D::context->RSSetViewports(1, &vp); + + // Color is passed in bgra mode so we need to convert it to rgba + u32 rgbaColor = (color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000); + D3D::drawClearQuad(rgbaColor, 1.0f - (z & 0xFFFFFF) / 16777216.0f); + + D3D::stateman->PopDepthState(); + D3D::stateman->PopBlendState(); + + RestoreAPIState(); } void Renderer::ReinterpretPixelData(unsigned int convtype) { - // TODO: MSAA support.. - D3D11_RECT source = CD3D11_RECT(0, 0, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight()); - - ID3D11PixelShader* pixel_shader; - if (convtype == 0) pixel_shader = PixelShaderCache::ReinterpRGB8ToRGBA6(true); - else if (convtype == 2) pixel_shader = PixelShaderCache::ReinterpRGBA6ToRGB8(true); - else - { - ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d", convtype); - return; - } - - // convert data and set the target texture as our new EFB - g_renderer->ResetAPIState(); - - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)g_renderer->GetTargetWidth(), (float)g_renderer->GetTargetHeight()); - D3D::context->RSSetViewports(1, &vp); - - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTempTexture()->GetRTV(), nullptr); - D3D::SetPointCopySampler(); - D3D::drawShadedTexQuad(FramebufferManager::GetEFBColorTexture()->GetSRV(), &source, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(), - pixel_shader, VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader()); - - g_renderer->RestoreAPIState(); - - FramebufferManager::SwapReinterpretTexture(); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); + // TODO: MSAA support.. + D3D11_RECT source = + CD3D11_RECT(0, 0, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight()); + + ID3D11PixelShader* pixel_shader; + if (convtype == 0) + pixel_shader = PixelShaderCache::ReinterpRGB8ToRGBA6(true); + else if (convtype == 2) + pixel_shader = PixelShaderCache::ReinterpRGBA6ToRGB8(true); + else + { + ERROR_LOG(VIDEO, "Trying to reinterpret pixel data with unsupported conversion type %d", + convtype); + return; + } + + // convert data and set the target texture as our new EFB + g_renderer->ResetAPIState(); + + D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)g_renderer->GetTargetWidth(), + (float)g_renderer->GetTargetHeight()); + D3D::context->RSSetViewports(1, &vp); + + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTempTexture()->GetRTV(), + nullptr); + D3D::SetPointCopySampler(); + D3D::drawShadedTexQuad( + FramebufferManager::GetEFBColorTexture()->GetSRV(), &source, g_renderer->GetTargetWidth(), + g_renderer->GetTargetHeight(), pixel_shader, VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader()); + + g_renderer->RestoreAPIState(); + + FramebufferManager::SwapReinterpretTexture(); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); } void Renderer::SetBlendMode(bool forceUpdate) { - // Our render target always uses an alpha channel, so we need to override the blend functions to assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel - // Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel is assumed to always be 1. - bool target_has_alpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; - const D3D11_BLEND d3dSrcFactors[8] = - { - D3D11_BLEND_ZERO, - D3D11_BLEND_ONE, - D3D11_BLEND_DEST_COLOR, - D3D11_BLEND_INV_DEST_COLOR, - D3D11_BLEND_SRC_ALPHA, - D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled! - (target_has_alpha) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE, - (target_has_alpha) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO - }; - const D3D11_BLEND d3dDestFactors[8] = - { - D3D11_BLEND_ZERO, - D3D11_BLEND_ONE, - D3D11_BLEND_SRC_COLOR, - D3D11_BLEND_INV_SRC_COLOR, - D3D11_BLEND_SRC_ALPHA, - D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled! - (target_has_alpha) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE, - (target_has_alpha) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO - }; - - if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable && !forceUpdate) - return; - - if (bpmem.blendmode.subtract) - { - gx_state.blend.blend_enable = true; - gx_state.blend.blend_op = D3D11_BLEND_OP_REV_SUBTRACT; - gx_state.blend.src_blend = D3D11_BLEND_ONE; - gx_state.blend.dst_blend = D3D11_BLEND_ONE; - } - else - { - gx_state.blend.blend_enable = (u32)bpmem.blendmode.blendenable; - if (bpmem.blendmode.blendenable) - { - gx_state.blend.blend_op = D3D11_BLEND_OP_ADD; - gx_state.blend.src_blend = d3dSrcFactors[bpmem.blendmode.srcfactor]; - gx_state.blend.dst_blend = d3dDestFactors[bpmem.blendmode.dstfactor]; - } - } + // Our render target always uses an alpha channel, so we need to override the blend functions to + // assume a destination alpha of 1 if the render target isn't supposed to have an alpha channel + // Example: D3DBLEND_DESTALPHA needs to be D3DBLEND_ONE since the result without an alpha channel + // is assumed to always be 1. + bool target_has_alpha = bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24; + const D3D11_BLEND d3dSrcFactors[8] = { + D3D11_BLEND_ZERO, + D3D11_BLEND_ONE, + D3D11_BLEND_DEST_COLOR, + D3D11_BLEND_INV_DEST_COLOR, + D3D11_BLEND_SRC_ALPHA, + D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled! + (target_has_alpha) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE, + (target_has_alpha) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO}; + const D3D11_BLEND d3dDestFactors[8] = { + D3D11_BLEND_ZERO, + D3D11_BLEND_ONE, + D3D11_BLEND_SRC_COLOR, + D3D11_BLEND_INV_SRC_COLOR, + D3D11_BLEND_SRC_ALPHA, + D3D11_BLEND_INV_SRC_ALPHA, // NOTE: Use SRC1_ALPHA if dst alpha is enabled! + (target_has_alpha) ? D3D11_BLEND_DEST_ALPHA : D3D11_BLEND_ONE, + (target_has_alpha) ? D3D11_BLEND_INV_DEST_ALPHA : D3D11_BLEND_ZERO}; + + if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable && !forceUpdate) + return; + + if (bpmem.blendmode.subtract) + { + gx_state.blend.blend_enable = true; + gx_state.blend.blend_op = D3D11_BLEND_OP_REV_SUBTRACT; + gx_state.blend.src_blend = D3D11_BLEND_ONE; + gx_state.blend.dst_blend = D3D11_BLEND_ONE; + } + else + { + gx_state.blend.blend_enable = (u32)bpmem.blendmode.blendenable; + if (bpmem.blendmode.blendenable) + { + gx_state.blend.blend_op = D3D11_BLEND_OP_ADD; + gx_state.blend.src_blend = d3dSrcFactors[bpmem.blendmode.srcfactor]; + gx_state.blend.dst_blend = d3dDestFactors[bpmem.blendmode.dstfactor]; + } + } } -bool Renderer::SaveScreenshot(const std::string &filename, const TargetRectangle& rc) +bool Renderer::SaveScreenshot(const std::string& filename, const TargetRectangle& rc) { - if (!s_screenshot_texture) - CreateScreenshotTexture(); - - // copy back buffer to system memory - D3D11_BOX source_box = GetScreenshotSourceBox(rc); - D3D::context->CopySubresourceRegion(s_screenshot_texture, 0, 0, 0, 0, (ID3D11Resource*)D3D::GetBackBuffer()->GetTex(), 0, &source_box); - - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ_WRITE, 0, &map); - - bool saved_png = TextureToPng((u8*)map.pData, map.RowPitch, filename, source_box.right - source_box.left, source_box.bottom - source_box.top, false); - - D3D::context->Unmap(s_screenshot_texture, 0); - - - if (saved_png) - { - OSD::AddMessage(StringFromFormat("Saved %i x %i %s", rc.GetWidth(), - rc.GetHeight(), filename.c_str())); - } - else - { - OSD::AddMessage(StringFromFormat("Error saving %s", filename.c_str())); - } - - return saved_png; + if (!s_screenshot_texture) + CreateScreenshotTexture(); + + // copy back buffer to system memory + D3D11_BOX source_box = GetScreenshotSourceBox(rc); + D3D::context->CopySubresourceRegion(s_screenshot_texture, 0, 0, 0, 0, + (ID3D11Resource*)D3D::GetBackBuffer()->GetTex(), 0, + &source_box); + + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ_WRITE, 0, &map); + + bool saved_png = + TextureToPng((u8*)map.pData, map.RowPitch, filename, source_box.right - source_box.left, + source_box.bottom - source_box.top, false); + + D3D::context->Unmap(s_screenshot_texture, 0); + + if (saved_png) + { + OSD::AddMessage( + StringFromFormat("Saved %i x %i %s", rc.GetWidth(), rc.GetHeight(), filename.c_str())); + } + else + { + OSD::AddMessage(StringFromFormat("Error saving %s", filename.c_str())); + } + + return saved_png; } void formatBufferDump(const u8* in, u8* out, int w, int h, int p) { - for (int y = 0; y < h; ++y) - { - auto line = (in + (h - y - 1) * p); - for (int x = 0; x < w; ++x) - { - out[0] = line[2]; - out[1] = line[1]; - out[2] = line[0]; - out += 3; - line += 4; - } - } + for (int y = 0; y < h; ++y) + { + auto line = (in + (h - y - 1) * p); + for (int x = 0; x < w; ++x) + { + out[0] = line[2]; + out[1] = line[1]; + out[2] = line[0]; + out += 3; + line += 4; + } + } } // This function has the final picture. We adjust the aspect ratio here. -void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc, float Gamma) +void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, + const EFBRectangle& rc, float Gamma) { - if (Fifo::WillSkipCurrentFrame() || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight) - { - if (SConfig::GetInstance().m_DumpFrames && !frame_data.empty()) - AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight); - - Core::Callback_VideoCopiedToXFB(false); - return; - } - - u32 xfbCount = 0; - const XFBSourceBase* const* xfbSourceList = FramebufferManager::GetXFBSource(xfbAddr, fbStride, fbHeight, &xfbCount); - if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) - { - if (SConfig::GetInstance().m_DumpFrames && !frame_data.empty()) - AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight); - - Core::Callback_VideoCopiedToXFB(false); - return; - } - - ResetAPIState(); - - // Prepare to copy the XFBs to our backbuffer - UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); - TargetRectangle targetRc = GetTargetRectangle(); - - D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); - - float ClearColor[4] = { 0.f, 0.f, 0.f, 1.f }; - D3D::context->ClearRenderTargetView(D3D::GetBackBuffer()->GetRTV(), ClearColor); - - // activate linear filtering for the buffer copies - D3D::SetLinearCopySampler(); - - if (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB) - { - // TODO: Television should be used to render Virtual XFB mode as well. - D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, (float)targetRc.GetWidth(), (float)targetRc.GetHeight()); - D3D::context->RSSetViewports(1, &vp); - - s_television.Submit(xfbAddr, fbStride, fbWidth, fbHeight); - s_television.Render(); - } - else if (g_ActiveConfig.bUseXFB) - { - const XFBSource* xfbSource; - - // draw each xfb source - for (u32 i = 0; i < xfbCount; ++i) - { - xfbSource = (const XFBSource*)xfbSourceList[i]; - - TargetRectangle drawRc; - - // use virtual xfb with offset - int xfbHeight = xfbSource->srcHeight; - int xfbWidth = xfbSource->srcWidth; - int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbStride * 2); - - drawRc.top = targetRc.top + hOffset * targetRc.GetHeight() / (s32)fbHeight; - drawRc.bottom = targetRc.top + (hOffset + xfbHeight) * targetRc.GetHeight() / (s32)fbHeight; - drawRc.left = targetRc.left + (targetRc.GetWidth() - xfbWidth * targetRc.GetWidth() / (s32)fbStride) / 2; - drawRc.right = targetRc.left + (targetRc.GetWidth() + xfbWidth * targetRc.GetWidth() / (s32)fbStride) / 2; - - // The following code disables auto stretch. Kept for reference. - // scale draw area for a 1 to 1 pixel mapping with the draw target - //float vScale = (float)fbHeight / (float)s_backbuffer_height; - //float hScale = (float)fbWidth / (float)s_backbuffer_width; - //drawRc.top *= vScale; - //drawRc.bottom *= vScale; - //drawRc.left *= hScale; - //drawRc.right *= hScale; - - TargetRectangle sourceRc; - sourceRc.left = xfbSource->sourceRc.left; - sourceRc.top = xfbSource->sourceRc.top; - sourceRc.right = xfbSource->sourceRc.right; - sourceRc.bottom = xfbSource->sourceRc.bottom; - - sourceRc.right -= Renderer::EFBToScaledX(fbStride - fbWidth); - - BlitScreen(sourceRc, drawRc, xfbSource->tex, xfbSource->texWidth, xfbSource->texHeight, Gamma); - } - } - else - { - TargetRectangle sourceRc = Renderer::ConvertEFBRectangle(rc); - - // TODO: Improve sampling algorithm for the pixel shader so that we can use the multisampled EFB texture as source - D3DTexture2D* read_texture = FramebufferManager::GetResolvedEFBColorTexture(); - BlitScreen(sourceRc, targetRc, read_texture, GetTargetWidth(), GetTargetHeight(), Gamma); - } - - // done with drawing the game stuff, good moment to save a screenshot - if (s_bScreenshot) - { - std::lock_guard<std::mutex> guard(s_criticalScreenshot); - - SaveScreenshot(s_sScreenshotName, GetTargetRectangle()); - s_sScreenshotName.clear(); - s_bScreenshot = false; - s_screenshotCompleted.Set(); - } - - // Dump frames - static int w = 0, h = 0; - if (SConfig::GetInstance().m_DumpFrames) - { - static int s_recordWidth; - static int s_recordHeight; - - if (!s_screenshot_texture) - CreateScreenshotTexture(); - - D3D11_BOX source_box = GetScreenshotSourceBox(targetRc); - unsigned int source_width = source_box.right - source_box.left; - unsigned int source_height = source_box.bottom - source_box.top; - D3D::context->CopySubresourceRegion(s_screenshot_texture, 0, 0, 0, 0, (ID3D11Resource*)D3D::GetBackBuffer()->GetTex(), 0, &source_box); - if (!bLastFrameDumped) - { - s_recordWidth = source_width; - s_recordHeight = source_height; - bAVIDumping = AVIDump::Start(s_recordWidth, s_recordHeight, AVIDump::DumpFormat::FORMAT_BGR); - if (!bAVIDumping) - { - PanicAlert("Error dumping frames to AVI."); - } - else - { - std::string msg = StringFromFormat("Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", - File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), s_recordWidth, s_recordHeight); - - OSD::AddMessage(msg, 2000); - } - } - if (bAVIDumping) - { - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ, 0, &map); - - if (frame_data.empty() || w != s_recordWidth || h != s_recordHeight) - { - frame_data.resize(3 * s_recordWidth * s_recordHeight); - w = s_recordWidth; - h = s_recordHeight; - } - formatBufferDump((u8*)map.pData, &frame_data[0], source_width, source_height, map.RowPitch); - FlipImageData(&frame_data[0], w, h); - AVIDump::AddFrame(&frame_data[0], source_width, source_height); - D3D::context->Unmap(s_screenshot_texture, 0); - } - bLastFrameDumped = true; - } - else - { - if (bLastFrameDumped && bAVIDumping) - { - std::vector<u8>().swap(frame_data); - w = h = 0; - - AVIDump::Stop(); - bAVIDumping = false; - OSD::AddMessage("Stop dumping frames to AVI", 2000); - } - bLastFrameDumped = false; - } - - // Reset viewport for drawing text - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetBackbufferWidth(), (float)GetBackbufferHeight()); - D3D::context->RSSetViewports(1, &vp); - - Renderer::DrawDebugText(); - - OSD::DrawMessages(); - D3D::EndFrame(); - - TextureCacheBase::Cleanup(frameCount); - - // Enable configuration changes - UpdateActiveConfig(); - TextureCacheBase::OnConfigChanged(g_ActiveConfig); - - SetWindowSize(fbStride, fbHeight); - - const bool windowResized = CheckForResize(); - const bool fullscreen = g_ActiveConfig.bFullscreen && !g_ActiveConfig.bBorderlessFullscreen && - !SConfig::GetInstance().bRenderToMain; - - bool xfbchanged = s_last_xfb_mode != g_ActiveConfig.bUseRealXFB; - - if (FramebufferManagerBase::LastXfbWidth() != fbStride || FramebufferManagerBase::LastXfbHeight() != fbHeight) - { - xfbchanged = true; - unsigned int xfb_w = (fbStride < 1 || fbStride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbStride; - unsigned int xfb_h = (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight; - FramebufferManagerBase::SetLastXfbWidth(xfb_w); - FramebufferManagerBase::SetLastXfbHeight(xfb_h); - } - - // Flip/present backbuffer to frontbuffer here - D3D::Present(); - - // Check exclusive fullscreen state - bool exclusive_mode, fullscreen_changed = false; - if (SUCCEEDED(D3D::GetFullscreenState(&exclusive_mode))) - { - if (fullscreen && !exclusive_mode) - { - if (g_Config.bExclusiveMode) - OSD::AddMessage("Lost exclusive fullscreen."); - - // Exclusive fullscreen is enabled in the configuration, but we're - // not in exclusive mode. Either exclusive fullscreen was turned on - // or the render frame lost focus. When the render frame is in focus - // we can apply exclusive mode. - fullscreen_changed = Host_RendererHasFocus(); - - g_Config.bExclusiveMode = false; - } - else if (!fullscreen && exclusive_mode) - { - // Exclusive fullscreen is disabled, but we're still in exclusive mode. - fullscreen_changed = true; - } - } - - // Resize the back buffers NOW to avoid flickering - if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height) || - xfbchanged || - windowResized || - fullscreen_changed || - s_last_efb_scale != g_ActiveConfig.iEFBScale || - s_last_multisamples != g_ActiveConfig.iMultisamples || - s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0)) - { - s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; - s_last_multisamples = g_ActiveConfig.iMultisamples; - PixelShaderCache::InvalidateMSAAShaders(); - - if (windowResized || fullscreen_changed) - { - // Apply fullscreen state - if (fullscreen_changed) - { - g_Config.bExclusiveMode = fullscreen; - - if (fullscreen) - OSD::AddMessage("Entered exclusive fullscreen."); - - D3D::SetFullscreenState(fullscreen); - - // If fullscreen is disabled we can safely notify the UI to exit fullscreen. - if (!g_ActiveConfig.bFullscreen) - Host_RequestFullscreen(false); - } - - // TODO: Aren't we still holding a reference to the back buffer right now? - D3D::Reset(); - SAFE_RELEASE(s_screenshot_texture); - SAFE_RELEASE(s_3d_vision_texture); - s_backbuffer_width = D3D::GetBackBufferWidth(); - s_backbuffer_height = D3D::GetBackBufferHeight(); - } - - UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); - - s_last_efb_scale = g_ActiveConfig.iEFBScale; - s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; - - PixelShaderManager::SetEfbScaleChanged(); - - D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); - - g_framebuffer_manager.reset(); - g_framebuffer_manager = std::make_unique<FramebufferManager>(); - float clear_col[4] = { 0.f, 0.f, 0.f, 1.f }; - D3D::context->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV(), clear_col); - D3D::context->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV(), D3D11_CLEAR_DEPTH, 0.f, 0); - } - - // begin next frame - RestoreAPIState(); - D3D::BeginFrame(); - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); - SetViewport(); + if (Fifo::WillSkipCurrentFrame() || (!XFBWrited && !g_ActiveConfig.RealXFBEnabled()) || + !fbWidth || !fbHeight) + { + if (SConfig::GetInstance().m_DumpFrames && !frame_data.empty()) + AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight); + + Core::Callback_VideoCopiedToXFB(false); + return; + } + + u32 xfbCount = 0; + const XFBSourceBase* const* xfbSourceList = + FramebufferManager::GetXFBSource(xfbAddr, fbStride, fbHeight, &xfbCount); + if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) + { + if (SConfig::GetInstance().m_DumpFrames && !frame_data.empty()) + AVIDump::AddFrame(&frame_data[0], fbWidth, fbHeight); + + Core::Callback_VideoCopiedToXFB(false); + return; + } + + ResetAPIState(); + + // Prepare to copy the XFBs to our backbuffer + UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); + TargetRectangle targetRc = GetTargetRectangle(); + + D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); + + float ClearColor[4] = {0.f, 0.f, 0.f, 1.f}; + D3D::context->ClearRenderTargetView(D3D::GetBackBuffer()->GetRTV(), ClearColor); + + // activate linear filtering for the buffer copies + D3D::SetLinearCopySampler(); + + if (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB) + { + // TODO: Television should be used to render Virtual XFB mode as well. + D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top, + (float)targetRc.GetWidth(), (float)targetRc.GetHeight()); + D3D::context->RSSetViewports(1, &vp); + + s_television.Submit(xfbAddr, fbStride, fbWidth, fbHeight); + s_television.Render(); + } + else if (g_ActiveConfig.bUseXFB) + { + const XFBSource* xfbSource; + + // draw each xfb source + for (u32 i = 0; i < xfbCount; ++i) + { + xfbSource = (const XFBSource*)xfbSourceList[i]; + + TargetRectangle drawRc; + + // use virtual xfb with offset + int xfbHeight = xfbSource->srcHeight; + int xfbWidth = xfbSource->srcWidth; + int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbStride * 2); + + drawRc.top = targetRc.top + hOffset * targetRc.GetHeight() / (s32)fbHeight; + drawRc.bottom = targetRc.top + (hOffset + xfbHeight) * targetRc.GetHeight() / (s32)fbHeight; + drawRc.left = targetRc.left + + (targetRc.GetWidth() - xfbWidth * targetRc.GetWidth() / (s32)fbStride) / 2; + drawRc.right = targetRc.left + + (targetRc.GetWidth() + xfbWidth * targetRc.GetWidth() / (s32)fbStride) / 2; + + // The following code disables auto stretch. Kept for reference. + // scale draw area for a 1 to 1 pixel mapping with the draw target + // float vScale = (float)fbHeight / (float)s_backbuffer_height; + // float hScale = (float)fbWidth / (float)s_backbuffer_width; + // drawRc.top *= vScale; + // drawRc.bottom *= vScale; + // drawRc.left *= hScale; + // drawRc.right *= hScale; + + TargetRectangle sourceRc; + sourceRc.left = xfbSource->sourceRc.left; + sourceRc.top = xfbSource->sourceRc.top; + sourceRc.right = xfbSource->sourceRc.right; + sourceRc.bottom = xfbSource->sourceRc.bottom; + + sourceRc.right -= Renderer::EFBToScaledX(fbStride - fbWidth); + + BlitScreen(sourceRc, drawRc, xfbSource->tex, xfbSource->texWidth, xfbSource->texHeight, + Gamma); + } + } + else + { + TargetRectangle sourceRc = Renderer::ConvertEFBRectangle(rc); + + // TODO: Improve sampling algorithm for the pixel shader so that we can use the multisampled EFB + // texture as source + D3DTexture2D* read_texture = FramebufferManager::GetResolvedEFBColorTexture(); + BlitScreen(sourceRc, targetRc, read_texture, GetTargetWidth(), GetTargetHeight(), Gamma); + } + + // done with drawing the game stuff, good moment to save a screenshot + if (s_bScreenshot) + { + std::lock_guard<std::mutex> guard(s_criticalScreenshot); + + SaveScreenshot(s_sScreenshotName, GetTargetRectangle()); + s_sScreenshotName.clear(); + s_bScreenshot = false; + s_screenshotCompleted.Set(); + } + + // Dump frames + static int w = 0, h = 0; + if (SConfig::GetInstance().m_DumpFrames) + { + static int s_recordWidth; + static int s_recordHeight; + + if (!s_screenshot_texture) + CreateScreenshotTexture(); + + D3D11_BOX source_box = GetScreenshotSourceBox(targetRc); + unsigned int source_width = source_box.right - source_box.left; + unsigned int source_height = source_box.bottom - source_box.top; + D3D::context->CopySubresourceRegion(s_screenshot_texture, 0, 0, 0, 0, + (ID3D11Resource*)D3D::GetBackBuffer()->GetTex(), 0, + &source_box); + if (!bLastFrameDumped) + { + s_recordWidth = source_width; + s_recordHeight = source_height; + bAVIDumping = AVIDump::Start(s_recordWidth, s_recordHeight, AVIDump::DumpFormat::FORMAT_BGR); + if (!bAVIDumping) + { + PanicAlert("Error dumping frames to AVI."); + } + else + { + std::string msg = StringFromFormat("Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", + File::GetUserPath(D_DUMPFRAMES_IDX).c_str(), + s_recordWidth, s_recordHeight); + + OSD::AddMessage(msg, 2000); + } + } + if (bAVIDumping) + { + D3D11_MAPPED_SUBRESOURCE map; + D3D::context->Map(s_screenshot_texture, 0, D3D11_MAP_READ, 0, &map); + + if (frame_data.empty() || w != s_recordWidth || h != s_recordHeight) + { + frame_data.resize(3 * s_recordWidth * s_recordHeight); + w = s_recordWidth; + h = s_recordHeight; + } + formatBufferDump((u8*)map.pData, &frame_data[0], source_width, source_height, map.RowPitch); + FlipImageData(&frame_data[0], w, h); + AVIDump::AddFrame(&frame_data[0], source_width, source_height); + D3D::context->Unmap(s_screenshot_texture, 0); + } + bLastFrameDumped = true; + } + else + { + if (bLastFrameDumped && bAVIDumping) + { + std::vector<u8>().swap(frame_data); + w = h = 0; + + AVIDump::Stop(); + bAVIDumping = false; + OSD::AddMessage("Stop dumping frames to AVI", 2000); + } + bLastFrameDumped = false; + } + + // Reset viewport for drawing text + D3D11_VIEWPORT vp = + CD3D11_VIEWPORT(0.0f, 0.0f, (float)GetBackbufferWidth(), (float)GetBackbufferHeight()); + D3D::context->RSSetViewports(1, &vp); + + Renderer::DrawDebugText(); + + OSD::DrawMessages(); + D3D::EndFrame(); + + TextureCacheBase::Cleanup(frameCount); + + // Enable configuration changes + UpdateActiveConfig(); + TextureCacheBase::OnConfigChanged(g_ActiveConfig); + + SetWindowSize(fbStride, fbHeight); + + const bool windowResized = CheckForResize(); + const bool fullscreen = g_ActiveConfig.bFullscreen && !g_ActiveConfig.bBorderlessFullscreen && + !SConfig::GetInstance().bRenderToMain; + + bool xfbchanged = s_last_xfb_mode != g_ActiveConfig.bUseRealXFB; + + if (FramebufferManagerBase::LastXfbWidth() != fbStride || + FramebufferManagerBase::LastXfbHeight() != fbHeight) + { + xfbchanged = true; + unsigned int xfb_w = (fbStride < 1 || fbStride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbStride; + unsigned int xfb_h = (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight; + FramebufferManagerBase::SetLastXfbWidth(xfb_w); + FramebufferManagerBase::SetLastXfbHeight(xfb_h); + } + + // Flip/present backbuffer to frontbuffer here + D3D::Present(); + + // Check exclusive fullscreen state + bool exclusive_mode, fullscreen_changed = false; + if (SUCCEEDED(D3D::GetFullscreenState(&exclusive_mode))) + { + if (fullscreen && !exclusive_mode) + { + if (g_Config.bExclusiveMode) + OSD::AddMessage("Lost exclusive fullscreen."); + + // Exclusive fullscreen is enabled in the configuration, but we're + // not in exclusive mode. Either exclusive fullscreen was turned on + // or the render frame lost focus. When the render frame is in focus + // we can apply exclusive mode. + fullscreen_changed = Host_RendererHasFocus(); + + g_Config.bExclusiveMode = false; + } + else if (!fullscreen && exclusive_mode) + { + // Exclusive fullscreen is disabled, but we're still in exclusive mode. + fullscreen_changed = true; + } + } + + // Resize the back buffers NOW to avoid flickering + if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height) || xfbchanged || windowResized || + fullscreen_changed || s_last_efb_scale != g_ActiveConfig.iEFBScale || + s_last_multisamples != g_ActiveConfig.iMultisamples || + s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0)) + { + s_last_xfb_mode = g_ActiveConfig.bUseRealXFB; + s_last_multisamples = g_ActiveConfig.iMultisamples; + PixelShaderCache::InvalidateMSAAShaders(); + + if (windowResized || fullscreen_changed) + { + // Apply fullscreen state + if (fullscreen_changed) + { + g_Config.bExclusiveMode = fullscreen; + + if (fullscreen) + OSD::AddMessage("Entered exclusive fullscreen."); + + D3D::SetFullscreenState(fullscreen); + + // If fullscreen is disabled we can safely notify the UI to exit fullscreen. + if (!g_ActiveConfig.bFullscreen) + Host_RequestFullscreen(false); + } + + // TODO: Aren't we still holding a reference to the back buffer right now? + D3D::Reset(); + SAFE_RELEASE(s_screenshot_texture); + SAFE_RELEASE(s_3d_vision_texture); + s_backbuffer_width = D3D::GetBackBufferWidth(); + s_backbuffer_height = D3D::GetBackBufferHeight(); + } + + UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height); + + s_last_efb_scale = g_ActiveConfig.iEFBScale; + s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0; + + PixelShaderManager::SetEfbScaleChanged(); + + D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); + + g_framebuffer_manager.reset(); + g_framebuffer_manager = std::make_unique<FramebufferManager>(); + float clear_col[4] = {0.f, 0.f, 0.f, 1.f}; + D3D::context->ClearRenderTargetView(FramebufferManager::GetEFBColorTexture()->GetRTV(), + clear_col); + D3D::context->ClearDepthStencilView(FramebufferManager::GetEFBDepthTexture()->GetDSV(), + D3D11_CLEAR_DEPTH, 0.f, 0); + } + + // begin next frame + RestoreAPIState(); + D3D::BeginFrame(); + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); + SetViewport(); } // ALWAYS call RestoreAPIState for each ResetAPIState call you're doing void Renderer::ResetAPIState() { - D3D::stateman->PushBlendState(resetblendstate); - D3D::stateman->PushDepthState(resetdepthstate); - D3D::stateman->PushRasterizerState(resetraststate); + D3D::stateman->PushBlendState(resetblendstate); + D3D::stateman->PushDepthState(resetdepthstate); + D3D::stateman->PushRasterizerState(resetraststate); } void Renderer::RestoreAPIState() { - // Gets us back into a more game-like state. - D3D::stateman->PopBlendState(); - D3D::stateman->PopDepthState(); - D3D::stateman->PopRasterizerState(); - SetViewport(); - BPFunctions::SetScissor(); + // Gets us back into a more game-like state. + D3D::stateman->PopBlendState(); + D3D::stateman->PopDepthState(); + D3D::stateman->PopRasterizerState(); + SetViewport(); + BPFunctions::SetScissor(); } void Renderer::ApplyState(bool bUseDstAlpha) { - gx_state.blend.use_dst_alpha = bUseDstAlpha; - D3D::stateman->PushBlendState(gx_state_cache.Get(gx_state.blend)); - D3D::stateman->PushDepthState(gx_state_cache.Get(gx_state.zmode)); - D3D::stateman->PushRasterizerState(gx_state_cache.Get(gx_state.raster)); - - for (unsigned int stage = 0; stage < 8; stage++) - { - // TODO: cache SamplerState directly, not d3d object - gx_state.sampler[stage].max_anisotropy = UINT64_C(1) << g_ActiveConfig.iMaxAnisotropy; - D3D::stateman->SetSampler(stage, gx_state_cache.Get(gx_state.sampler[stage])); - } - - if (bUseDstAlpha) - { - // restore actual state - SetBlendMode(false); - SetLogicOpMode(); - } - - ID3D11Buffer* vertexConstants = VertexShaderCache::GetConstantBuffer(); - - D3D::stateman->SetPixelConstants(PixelShaderCache::GetConstantBuffer(), g_ActiveConfig.bEnablePixelLighting ? vertexConstants : nullptr); - D3D::stateman->SetVertexConstants(vertexConstants); - D3D::stateman->SetGeometryConstants(GeometryShaderCache::GetConstantBuffer()); - - D3D::stateman->SetPixelShader(PixelShaderCache::GetActiveShader()); - D3D::stateman->SetVertexShader(VertexShaderCache::GetActiveShader()); - D3D::stateman->SetGeometryShader(GeometryShaderCache::GetActiveShader()); + gx_state.blend.use_dst_alpha = bUseDstAlpha; + D3D::stateman->PushBlendState(gx_state_cache.Get(gx_state.blend)); + D3D::stateman->PushDepthState(gx_state_cache.Get(gx_state.zmode)); + D3D::stateman->PushRasterizerState(gx_state_cache.Get(gx_state.raster)); + + for (unsigned int stage = 0; stage < 8; stage++) + { + // TODO: cache SamplerState directly, not d3d object + gx_state.sampler[stage].max_anisotropy = UINT64_C(1) << g_ActiveConfig.iMaxAnisotropy; + D3D::stateman->SetSampler(stage, gx_state_cache.Get(gx_state.sampler[stage])); + } + + if (bUseDstAlpha) + { + // restore actual state + SetBlendMode(false); + SetLogicOpMode(); + } + + ID3D11Buffer* vertexConstants = VertexShaderCache::GetConstantBuffer(); + + D3D::stateman->SetPixelConstants(PixelShaderCache::GetConstantBuffer(), + g_ActiveConfig.bEnablePixelLighting ? vertexConstants : nullptr); + D3D::stateman->SetVertexConstants(vertexConstants); + D3D::stateman->SetGeometryConstants(GeometryShaderCache::GetConstantBuffer()); + + D3D::stateman->SetPixelShader(PixelShaderCache::GetActiveShader()); + D3D::stateman->SetVertexShader(VertexShaderCache::GetActiveShader()); + D3D::stateman->SetGeometryShader(GeometryShaderCache::GetActiveShader()); } void Renderer::RestoreState() { - D3D::stateman->PopBlendState(); - D3D::stateman->PopDepthState(); - D3D::stateman->PopRasterizerState(); + D3D::stateman->PopBlendState(); + D3D::stateman->PopDepthState(); + D3D::stateman->PopRasterizerState(); } void Renderer::ApplyCullDisable() { - RasterizerState rast = gx_state.raster; - rast.cull_mode = D3D11_CULL_NONE; + RasterizerState rast = gx_state.raster; + rast.cull_mode = D3D11_CULL_NONE; - ID3D11RasterizerState* raststate = gx_state_cache.Get(rast); - D3D::stateman->PushRasterizerState(raststate); + ID3D11RasterizerState* raststate = gx_state_cache.Get(rast); + D3D::stateman->PushRasterizerState(raststate); } void Renderer::RestoreCull() { - D3D::stateman->PopRasterizerState(); + D3D::stateman->PopRasterizerState(); } void Renderer::SetGenerationMode() { - const D3D11_CULL_MODE d3dCullModes[4] = - { - D3D11_CULL_NONE, - D3D11_CULL_BACK, - D3D11_CULL_FRONT, - D3D11_CULL_BACK - }; - - // rastdc.FrontCounterClockwise must be false for this to work - // TODO: GX_CULL_ALL not supported, yet! - gx_state.raster.cull_mode = d3dCullModes[bpmem.genMode.cullmode]; + const D3D11_CULL_MODE d3dCullModes[4] = {D3D11_CULL_NONE, D3D11_CULL_BACK, D3D11_CULL_FRONT, + D3D11_CULL_BACK}; + + // rastdc.FrontCounterClockwise must be false for this to work + // TODO: GX_CULL_ALL not supported, yet! + gx_state.raster.cull_mode = d3dCullModes[bpmem.genMode.cullmode]; } void Renderer::SetDepthMode() { - gx_state.zmode.hex = bpmem.zmode.hex; + gx_state.zmode.hex = bpmem.zmode.hex; } void Renderer::SetLogicOpMode() { - // D3D11 doesn't support logic blending, so this is a huge hack - // TODO: Make use of D3D11.1's logic blending support - - // 0 0x00 - // 1 Source & destination - // 2 Source & ~destination - // 3 Source - // 4 ~Source & destination - // 5 Destination - // 6 Source ^ destination = Source & ~destination | ~Source & destination - // 7 Source | destination - // 8 ~(Source | destination) - // 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination - // 10 ~Destination - // 11 Source | ~destination - // 12 ~Source - // 13 ~Source | destination - // 14 ~(Source & destination) - // 15 0xff - const D3D11_BLEND_OP d3dLogicOps[16] = - { - D3D11_BLEND_OP_ADD,//0 - D3D11_BLEND_OP_ADD,//1 - D3D11_BLEND_OP_SUBTRACT,//2 - D3D11_BLEND_OP_ADD,//3 - D3D11_BLEND_OP_REV_SUBTRACT,//4 - D3D11_BLEND_OP_ADD,//5 - D3D11_BLEND_OP_MAX,//6 - D3D11_BLEND_OP_ADD,//7 - D3D11_BLEND_OP_MAX,//8 - D3D11_BLEND_OP_MAX,//9 - D3D11_BLEND_OP_ADD,//10 - D3D11_BLEND_OP_ADD,//11 - D3D11_BLEND_OP_ADD,//12 - D3D11_BLEND_OP_ADD,//13 - D3D11_BLEND_OP_ADD,//14 - D3D11_BLEND_OP_ADD//15 - }; - const D3D11_BLEND d3dLogicOpSrcFactors[16] = - { - D3D11_BLEND_ZERO,//0 - D3D11_BLEND_DEST_COLOR,//1 - D3D11_BLEND_ONE,//2 - D3D11_BLEND_ONE,//3 - D3D11_BLEND_DEST_COLOR,//4 - D3D11_BLEND_ZERO,//5 - D3D11_BLEND_INV_DEST_COLOR,//6 - D3D11_BLEND_INV_DEST_COLOR,//7 - D3D11_BLEND_INV_SRC_COLOR,//8 - D3D11_BLEND_INV_SRC_COLOR,//9 - D3D11_BLEND_INV_DEST_COLOR,//10 - D3D11_BLEND_ONE,//11 - D3D11_BLEND_INV_SRC_COLOR,//12 - D3D11_BLEND_INV_SRC_COLOR,//13 - D3D11_BLEND_INV_DEST_COLOR,//14 - D3D11_BLEND_ONE//15 - }; - const D3D11_BLEND d3dLogicOpDestFactors[16] = - { - D3D11_BLEND_ZERO,//0 - D3D11_BLEND_ZERO,//1 - D3D11_BLEND_INV_SRC_COLOR,//2 - D3D11_BLEND_ZERO,//3 - D3D11_BLEND_ONE,//4 - D3D11_BLEND_ONE,//5 - D3D11_BLEND_INV_SRC_COLOR,//6 - D3D11_BLEND_ONE,//7 - D3D11_BLEND_INV_DEST_COLOR,//8 - D3D11_BLEND_SRC_COLOR,//9 - D3D11_BLEND_INV_DEST_COLOR,//10 - D3D11_BLEND_INV_DEST_COLOR,//11 - D3D11_BLEND_INV_SRC_COLOR,//12 - D3D11_BLEND_ONE,//13 - D3D11_BLEND_INV_SRC_COLOR,//14 - D3D11_BLEND_ONE//15 - }; - - if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable) - { - gx_state.blend.blend_enable = true; - gx_state.blend.blend_op = d3dLogicOps[bpmem.blendmode.logicmode]; - gx_state.blend.src_blend = d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]; - gx_state.blend.dst_blend = d3dLogicOpDestFactors[bpmem.blendmode.logicmode]; - } - else - { - SetBlendMode(true); - } + // D3D11 doesn't support logic blending, so this is a huge hack + // TODO: Make use of D3D11.1's logic blending support + + // 0 0x00 + // 1 Source & destination + // 2 Source & ~destination + // 3 Source + // 4 ~Source & destination + // 5 Destination + // 6 Source ^ destination = Source & ~destination | ~Source & destination + // 7 Source | destination + // 8 ~(Source | destination) + // 9 ~(Source ^ destination) = ~Source & ~destination | Source & destination + // 10 ~Destination + // 11 Source | ~destination + // 12 ~Source + // 13 ~Source | destination + // 14 ~(Source & destination) + // 15 0xff + const D3D11_BLEND_OP d3dLogicOps[16] = { + D3D11_BLEND_OP_ADD, // 0 + D3D11_BLEND_OP_ADD, // 1 + D3D11_BLEND_OP_SUBTRACT, // 2 + D3D11_BLEND_OP_ADD, // 3 + D3D11_BLEND_OP_REV_SUBTRACT, // 4 + D3D11_BLEND_OP_ADD, // 5 + D3D11_BLEND_OP_MAX, // 6 + D3D11_BLEND_OP_ADD, // 7 + D3D11_BLEND_OP_MAX, // 8 + D3D11_BLEND_OP_MAX, // 9 + D3D11_BLEND_OP_ADD, // 10 + D3D11_BLEND_OP_ADD, // 11 + D3D11_BLEND_OP_ADD, // 12 + D3D11_BLEND_OP_ADD, // 13 + D3D11_BLEND_OP_ADD, // 14 + D3D11_BLEND_OP_ADD // 15 + }; + const D3D11_BLEND d3dLogicOpSrcFactors[16] = { + D3D11_BLEND_ZERO, // 0 + D3D11_BLEND_DEST_COLOR, // 1 + D3D11_BLEND_ONE, // 2 + D3D11_BLEND_ONE, // 3 + D3D11_BLEND_DEST_COLOR, // 4 + D3D11_BLEND_ZERO, // 5 + D3D11_BLEND_INV_DEST_COLOR, // 6 + D3D11_BLEND_INV_DEST_COLOR, // 7 + D3D11_BLEND_INV_SRC_COLOR, // 8 + D3D11_BLEND_INV_SRC_COLOR, // 9 + D3D11_BLEND_INV_DEST_COLOR, // 10 + D3D11_BLEND_ONE, // 11 + D3D11_BLEND_INV_SRC_COLOR, // 12 + D3D11_BLEND_INV_SRC_COLOR, // 13 + D3D11_BLEND_INV_DEST_COLOR, // 14 + D3D11_BLEND_ONE // 15 + }; + const D3D11_BLEND d3dLogicOpDestFactors[16] = { + D3D11_BLEND_ZERO, // 0 + D3D11_BLEND_ZERO, // 1 + D3D11_BLEND_INV_SRC_COLOR, // 2 + D3D11_BLEND_ZERO, // 3 + D3D11_BLEND_ONE, // 4 + D3D11_BLEND_ONE, // 5 + D3D11_BLEND_INV_SRC_COLOR, // 6 + D3D11_BLEND_ONE, // 7 + D3D11_BLEND_INV_DEST_COLOR, // 8 + D3D11_BLEND_SRC_COLOR, // 9 + D3D11_BLEND_INV_DEST_COLOR, // 10 + D3D11_BLEND_INV_DEST_COLOR, // 11 + D3D11_BLEND_INV_SRC_COLOR, // 12 + D3D11_BLEND_ONE, // 13 + D3D11_BLEND_INV_SRC_COLOR, // 14 + D3D11_BLEND_ONE // 15 + }; + + if (bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable) + { + gx_state.blend.blend_enable = true; + gx_state.blend.blend_op = d3dLogicOps[bpmem.blendmode.logicmode]; + gx_state.blend.src_blend = d3dLogicOpSrcFactors[bpmem.blendmode.logicmode]; + gx_state.blend.dst_blend = d3dLogicOpDestFactors[bpmem.blendmode.logicmode]; + } + else + { + SetBlendMode(true); + } } void Renderer::SetDitherMode() { - // TODO: Set dither mode to bpmem.blendmode.dither + // TODO: Set dither mode to bpmem.blendmode.dither } void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex) { - const FourTexUnits &tex = bpmem.tex[texindex]; - const TexMode0 &tm0 = tex.texMode0[stage]; - const TexMode1 &tm1 = tex.texMode1[stage]; - - if (texindex) - stage += 4; - - if (g_ActiveConfig.bForceFiltering) - { - // Only use mipmaps if the game says they are available. - gx_state.sampler[stage].min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4; - gx_state.sampler[stage].mag_filter = 1; // linear mag - } - else - { - gx_state.sampler[stage].min_filter = (u32)tm0.min_filter; - gx_state.sampler[stage].mag_filter = (u32)tm0.mag_filter; - } - - gx_state.sampler[stage].wrap_s = (u32)tm0.wrap_s; - gx_state.sampler[stage].wrap_t = (u32)tm0.wrap_t; - gx_state.sampler[stage].max_lod = (u32)tm1.max_lod; - gx_state.sampler[stage].min_lod = (u32)tm1.min_lod; - gx_state.sampler[stage].lod_bias = (s32)tm0.lod_bias; - - // custom textures may have higher resolution, so disable the max_lod - if (custom_tex) - { - gx_state.sampler[stage].max_lod = 255; - } + const FourTexUnits& tex = bpmem.tex[texindex]; + const TexMode0& tm0 = tex.texMode0[stage]; + const TexMode1& tm1 = tex.texMode1[stage]; + + if (texindex) + stage += 4; + + if (g_ActiveConfig.bForceFiltering) + { + // Only use mipmaps if the game says they are available. + gx_state.sampler[stage].min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4; + gx_state.sampler[stage].mag_filter = 1; // linear mag + } + else + { + gx_state.sampler[stage].min_filter = (u32)tm0.min_filter; + gx_state.sampler[stage].mag_filter = (u32)tm0.mag_filter; + } + + gx_state.sampler[stage].wrap_s = (u32)tm0.wrap_s; + gx_state.sampler[stage].wrap_t = (u32)tm0.wrap_t; + gx_state.sampler[stage].max_lod = (u32)tm1.max_lod; + gx_state.sampler[stage].min_lod = (u32)tm1.min_lod; + gx_state.sampler[stage].lod_bias = (s32)tm0.lod_bias; + + // custom textures may have higher resolution, so disable the max_lod + if (custom_tex) + { + gx_state.sampler[stage].max_lod = 255; + } } void Renderer::SetInterlacingMode() { - // TODO + // TODO } int Renderer::GetMaxTextureSize() { - return DX11::D3D::GetMaxTextureSize(); + return DX11::D3D::GetMaxTextureSize(); } u16 Renderer::BBoxRead(int index) { - // Here we get the min/max value of the truncated position of the upscaled framebuffer. - // So we have to correct them to the unscaled EFB sizes. - int value = BBox::Get(index); - - if (index < 2) - { - // left/right - value = value * EFB_WIDTH / s_target_width; - } - else - { - // up/down - value = value * EFB_HEIGHT / s_target_height; - } - if (index & 1) - value++; // fix max values to describe the outer border - - return value; + // Here we get the min/max value of the truncated position of the upscaled framebuffer. + // So we have to correct them to the unscaled EFB sizes. + int value = BBox::Get(index); + + if (index < 2) + { + // left/right + value = value * EFB_WIDTH / s_target_width; + } + else + { + // up/down + value = value * EFB_HEIGHT / s_target_height; + } + if (index & 1) + value++; // fix max values to describe the outer border + + return value; } void Renderer::BBoxWrite(int index, u16 _value) { - int value = _value; // u16 isn't enough to multiply by the efb width - if (index & 1) - value--; - if (index < 2) - { - value = value * s_target_width / EFB_WIDTH; - } - else - { - value = value * s_target_height / EFB_HEIGHT; - } - - BBox::Set(index, value); + int value = _value; // u16 isn't enough to multiply by the efb width + if (index & 1) + value--; + if (index < 2) + { + value = value * s_target_width / EFB_WIDTH; + } + else + { + value = value * s_target_height / EFB_HEIGHT; + } + + BBox::Set(index, value); } -void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, u32 src_width, u32 src_height, float Gamma) +void Renderer::BlitScreen(TargetRectangle src, TargetRectangle dst, D3DTexture2D* src_texture, + u32 src_width, u32 src_height, float Gamma) { - if (g_ActiveConfig.iStereoMode == STEREO_SBS || g_ActiveConfig.iStereoMode == STEREO_TAB) - { - TargetRectangle leftRc, rightRc; - ConvertStereoRectangle(dst, leftRc, rightRc); - - D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT((float)leftRc.left, (float)leftRc.top, (float)leftRc.GetWidth(), (float)leftRc.GetHeight()); - D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT((float)rightRc.left, (float)rightRc.top, (float)rightRc.GetWidth(), (float)rightRc.GetHeight()); - - D3D::context->RSSetViewports(1, &leftVp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0); - - D3D::context->RSSetViewports(1, &rightVp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 1); - } - else if (g_ActiveConfig.iStereoMode == STEREO_3DVISION) - { - if (!s_3d_vision_texture) - Create3DVisionTexture(s_backbuffer_width, s_backbuffer_height); - - D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT((float)dst.left, (float)dst.top, (float)dst.GetWidth(), (float)dst.GetHeight()); - D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT((float)(dst.left + s_backbuffer_width), (float)dst.top, (float)dst.GetWidth(), (float)dst.GetHeight()); - - // Render to staging texture which is double the width of the backbuffer - D3D::context->OMSetRenderTargets(1, &s_3d_vision_texture->GetRTV(), nullptr); - - D3D::context->RSSetViewports(1, &leftVp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0); - - D3D::context->RSSetViewports(1, &rightVp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 1); - - // Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should - // recognize the signature and automatically include the right eye frame. - D3D11_BOX box = CD3D11_BOX(0, 0, 0, s_backbuffer_width, s_backbuffer_height, 1); - D3D::context->CopySubresourceRegion(D3D::GetBackBuffer()->GetTex(), 0, 0, 0, 0, s_3d_vision_texture->GetTex(), 0, &box); - - // Restore render target to backbuffer - D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); - } - else - { - D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)dst.left, (float)dst.top, (float)dst.GetWidth(), (float)dst.GetHeight()); - D3D::context->RSSetViewports(1, &vp); - D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, (g_Config.iStereoMode == STEREO_ANAGLYPH) ? PixelShaderCache::GetAnaglyphProgram() : PixelShaderCache::GetColorCopyProgram(false), VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma); - } + if (g_ActiveConfig.iStereoMode == STEREO_SBS || g_ActiveConfig.iStereoMode == STEREO_TAB) + { + TargetRectangle leftRc, rightRc; + ConvertStereoRectangle(dst, leftRc, rightRc); + + D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT((float)leftRc.left, (float)leftRc.top, + (float)leftRc.GetWidth(), (float)leftRc.GetHeight()); + D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT((float)rightRc.left, (float)rightRc.top, + (float)rightRc.GetWidth(), (float)rightRc.GetHeight()); + + D3D::context->RSSetViewports(1, &leftVp); + D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + PixelShaderCache::GetColorCopyProgram(false), + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0); + + D3D::context->RSSetViewports(1, &rightVp); + D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + PixelShaderCache::GetColorCopyProgram(false), + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 1); + } + else if (g_ActiveConfig.iStereoMode == STEREO_3DVISION) + { + if (!s_3d_vision_texture) + Create3DVisionTexture(s_backbuffer_width, s_backbuffer_height); + + D3D11_VIEWPORT leftVp = CD3D11_VIEWPORT((float)dst.left, (float)dst.top, (float)dst.GetWidth(), + (float)dst.GetHeight()); + D3D11_VIEWPORT rightVp = CD3D11_VIEWPORT((float)(dst.left + s_backbuffer_width), (float)dst.top, + (float)dst.GetWidth(), (float)dst.GetHeight()); + + // Render to staging texture which is double the width of the backbuffer + D3D::context->OMSetRenderTargets(1, &s_3d_vision_texture->GetRTV(), nullptr); + + D3D::context->RSSetViewports(1, &leftVp); + D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + PixelShaderCache::GetColorCopyProgram(false), + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 0); + + D3D::context->RSSetViewports(1, &rightVp); + D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + PixelShaderCache::GetColorCopyProgram(false), + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma, 1); + + // Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should + // recognize the signature and automatically include the right eye frame. + D3D11_BOX box = CD3D11_BOX(0, 0, 0, s_backbuffer_width, s_backbuffer_height, 1); + D3D::context->CopySubresourceRegion(D3D::GetBackBuffer()->GetTex(), 0, 0, 0, 0, + s_3d_vision_texture->GetTex(), 0, &box); + + // Restore render target to backbuffer + D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr); + } + else + { + D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)dst.left, (float)dst.top, (float)dst.GetWidth(), + (float)dst.GetHeight()); + D3D::context->RSSetViewports(1, &vp); + D3D::drawShadedTexQuad(src_texture->GetSRV(), src.AsRECT(), src_width, src_height, + (g_Config.iStereoMode == STEREO_ANAGLYPH) ? + PixelShaderCache::GetAnaglyphProgram() : + PixelShaderCache::GetColorCopyProgram(false), + VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), nullptr, Gamma); + } } } // namespace DX11 |
